Skip to content

Commit 30d1960

Browse files
feat: adjust user_ssh_key to new structure
1 parent b05e59e commit 30d1960

3 files changed

Lines changed: 117 additions & 70 deletions

File tree

github/acc_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,11 @@ func configureSweepers() {
205205
F: sweepTeams,
206206
})
207207

208+
resource.AddTestSweepers("user_ssh_keys", &resource.Sweeper{
209+
Name: "user_ssh_keys",
210+
F: sweepUserSSHKeys,
211+
})
212+
208213
resource.AddTestSweepers("user_ssh_signing_keys", &resource.Sweeper{
209214
Name: "user_ssh_signing_keys",
210215
F: sweepUserSSHSigningKeys,
@@ -281,6 +286,36 @@ func sweepRepositories(_ string) error {
281286
return nil
282287
}
283288

289+
func sweepUserSSHKeys(_ string) error {
290+
fmt.Println("sweeping user SSH keys")
291+
292+
meta, err := getTestMeta()
293+
if err != nil {
294+
return fmt.Errorf("could not get test meta for sweeper: %w", err)
295+
}
296+
297+
client := meta.v3client
298+
owner := meta.name
299+
ctx := context.Background()
300+
301+
keys, _, err := client.Users.ListSSHKeys(ctx, owner, nil)
302+
if err != nil {
303+
return err
304+
}
305+
306+
for _, k := range keys {
307+
if title := k.GetTitle(); strings.HasPrefix(title, testResourcePrefix) {
308+
fmt.Printf("destroying user SSH key %s\n", title)
309+
310+
if _, err := client.Users.DeleteSSHKey(ctx, k.GetID()); err != nil {
311+
return err
312+
}
313+
}
314+
}
315+
316+
return nil
317+
}
318+
284319
func sweepUserSSHSigningKeys(_ string) error {
285320
fmt.Println("sweeping user SSH signing keys")
286321

github/resource_github_user_ssh_key.go

Lines changed: 69 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ func resourceGithubUserSshKey() *schema.Resource {
1818
Read: resourceGithubUserSshKeyRead,
1919
Delete: resourceGithubUserSshKeyDelete,
2020
Importer: &schema.ResourceImporter{
21-
StateContext: schema.ImportStatePassthroughContext,
21+
StateContext: resourceGithubUserSshKeyImport,
2222
},
2323

2424
Schema: map[string]*schema.Schema{
@@ -33,15 +33,11 @@ func resourceGithubUserSshKey() *schema.Resource {
3333
Required: true,
3434
ForceNew: true,
3535
Description: "The public SSH key to add to your GitHub account.",
36-
DiffSuppressFunc: func(k, oldV, newV string, d *schema.ResourceData) bool {
37-
newTrimmed := strings.TrimSpace(newV)
38-
return oldV == newTrimmed
39-
},
4036
},
41-
"url": {
42-
Type: schema.TypeString,
43-
Computed: true,
44-
Description: "The URL of the SSH key.",
37+
"key_id": {
38+
Type: schema.TypeInt,
39+
Computed: true,
40+
Description: "The unique identifier of the SSH key.",
4541
},
4642
"etag": {
4743
Type: schema.TypeString,
@@ -51,80 +47,103 @@ func resourceGithubUserSshKey() *schema.Resource {
5147
}
5248
}
5349

54-
func resourceGithubUserSshKeyCreate(d *schema.ResourceData, meta any) error {
50+
func resourceGithubUserSshKeyCreate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
5551
client := meta.(*Owner).v3client
5652

5753
title := d.Get("title").(string)
5854
key := d.Get("key").(string)
59-
ctx := context.Background()
6055

61-
userKey, _, err := client.Users.CreateKey(ctx, &github.Key{
56+
userKey, resp, err := client.Users.CreateKey(ctx, &github.Key{
6257
Title: github.Ptr(title),
6358
Key: github.Ptr(key),
6459
})
6560
if err != nil {
66-
return err
61+
return diag.FromErr(err)
6762
}
6863

69-
d.SetId(strconv.FormatInt(*userKey.ID, 10))
64+
d.SetId(strconv.FormatInt(userKey.GetID(), 10))
65+
66+
if err = d.Set("key_id", userKey.GetID()); err != nil {
67+
return diag.FromErr(err)
68+
}
69+
if err = d.Set("etag", resp.Header.Get("ETag")); err != nil {
70+
return diag.FromErr(err)
71+
}
72+
if err = d.Set("title", userKey.GetTitle()); err != nil {
73+
return diag.FromErr(err)
74+
}
75+
if err = d.Set("key", userKey.GetKey()); err != nil {
76+
return diag.FromErr(err)
77+
}
7078

71-
return resourceGithubUserSshKeyRead(d, meta)
79+
return nil
7280
}
7381

74-
func resourceGithubUserSshKeyRead(d *schema.ResourceData, meta any) error {
82+
func resourceGithubUserSshKeyRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
7583
client := meta.(*Owner).v3client
7684

77-
id, err := strconv.ParseInt(d.Id(), 10, 64)
78-
if err != nil {
79-
return unconvertibleIdErr(d.Id(), err)
80-
}
81-
ctx := context.WithValue(context.Background(), ctxId, d.Id())
82-
if !d.IsNewResource() {
83-
ctx = context.WithValue(ctx, ctxEtag, d.Get("etag").(string))
84-
}
85-
86-
key, resp, err := client.Users.GetKey(ctx, id)
85+
keyID := d.Get("key_id").(int64)
86+
key, resp, err := client.Users.GetKey(ctx, keyID)
8787
if err != nil {
88-
var ghErr *github.ErrorResponse
89-
if errors.As(err, &ghErr) {
88+
if ghErr, ok := err.(*github.ErrorResponse); ok {
9089
if ghErr.Response.StatusCode == http.StatusNotModified {
9190
return nil
9291
}
9392
if ghErr.Response.StatusCode == http.StatusNotFound {
94-
log.Printf("[INFO] Removing user SSH key %s from state because it no longer exists in GitHub",
95-
d.Id())
93+
tflog.Info(ctx, fmt.Sprintf("Removing user SSH key %s from state because it no longer exists in GitHub", d.Id()), map[string]any{
94+
"ssh_key_id": d.Id(),
95+
})
9696
d.SetId("")
9797
return nil
9898
}
9999
}
100-
return err
101100
}
101+
return nil
102+
}
102103

103-
if err = d.Set("etag", resp.Header.Get("ETag")); err != nil {
104-
return err
105-
}
106-
if err = d.Set("title", key.GetTitle()); err != nil {
107-
return err
108-
}
109-
if err = d.Set("key", key.GetKey()); err != nil {
110-
return err
111-
}
112-
if err = d.Set("url", key.GetURL()); err != nil {
113-
return err
114-
}
104+
func resourceGithubUserSshKeyDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics {
105+
client := meta.(*Owner).v3client
115106

116-
return nil
107+
keyID := d.Get("key_id").(int64)
108+
resp, err := client.Users.DeleteKey(ctx, keyID)
109+
if resp.StatusCode == http.StatusNotFound {
110+
return nil
111+
}
112+
return diag.FromErr(err)
117113
}
118114

119-
func resourceGithubUserSshKeyDelete(d *schema.ResourceData, meta any) error {
115+
func resourceGithubUserSshKeyImport(ctx context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) {
120116
client := meta.(*Owner).v3client
121117

122-
id, err := strconv.ParseInt(d.Id(), 10, 64)
118+
keyID, err := strconv.ParseInt(d.Id(), 10, 64)
123119
if err != nil {
124-
return unconvertibleIdErr(d.Id(), err)
120+
return nil, fmt.Errorf("invalid SSH key ID format: %v", err)
121+
}
122+
123+
key, resp, err := client.Users.GetKey(ctx, keyID)
124+
if err != nil {
125+
if ghErr, ok := err.(*github.ErrorResponse); ok {
126+
if ghErr.Response.StatusCode == http.StatusNotFound {
127+
return nil, fmt.Errorf("SSH key with ID %d not found", keyID)
128+
}
129+
}
130+
return nil, err
131+
}
132+
133+
d.SetId(strconv.FormatInt(key.GetID(), 10))
134+
135+
if err = d.Set("key_id", key.GetID()); err != nil {
136+
return nil, err
137+
}
138+
if err = d.Set("etag", resp.Header.Get("ETag")); err != nil {
139+
return nil, err
140+
}
141+
if err = d.Set("title", key.GetTitle()); err != nil {
142+
return nil, err
143+
}
144+
if err = d.Set("key", key.GetKey()); err != nil {
145+
return nil, err
125146
}
126-
ctx := context.WithValue(context.Background(), ctxId, d.Id())
127147

128-
_, err = client.Users.DeleteKey(ctx, id)
129-
return err
148+
return []*schema.ResourceData{d}, nil
130149
}

github/resource_github_user_ssh_key_test.go

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,19 @@ import (
1616
func TestAccGithubUserSshKey(t *testing.T) {
1717
t.Run("creates and destroys a user SSH key without error", func(t *testing.T) {
1818
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
19+
name := fmt.Sprintf(`%s-%s`, testResourcePrefix, randomID)
1920
testKey := newTestKey()
21+
2022
config := fmt.Sprintf(`
2123
resource "github_user_ssh_key" "test" {
22-
title = "tf-acc-test-%s"
23-
key = "%s"
24+
title = "%[1]s"
25+
key = "%[2]s"
2426
}
25-
`, randomID, testKey)
27+
`, name, testKey)
2628

2729
check := resource.ComposeTestCheckFunc(
28-
resource.TestMatchResourceAttr(
29-
"github_user_ssh_key.test", "title",
30-
regexp.MustCompile(randomID),
31-
),
32-
resource.TestMatchResourceAttr(
33-
"github_user_ssh_key.test", "key",
34-
regexp.MustCompile("^ssh-rsa "),
35-
),
36-
resource.TestMatchResourceAttr(
37-
"github_user_ssh_key.test", "url",
38-
regexp.MustCompile("^https://api.github.com/[a-z0-9]+/keys/"),
39-
),
30+
resource.TestMatchResourceAttr("github_user_ssh_key.test", "title", regexp.MustCompile(randomID)),
31+
resource.TestMatchResourceAttr("github_user_ssh_key.test", "key", regexp.MustCompile("^ssh-rsa ")),
4032
)
4133

4234
resource.Test(t, resource.TestCase{
@@ -53,13 +45,15 @@ func TestAccGithubUserSshKey(t *testing.T) {
5345

5446
t.Run("imports an individual account SSH key without error", func(t *testing.T) {
5547
randomID := acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
48+
name := fmt.Sprintf(`%s-%s`, testResourcePrefix, randomID)
5649
testKey := newTestKey()
50+
5751
config := fmt.Sprintf(`
5852
resource "github_user_ssh_key" "test" {
59-
title = "tf-acc-test-%s"
60-
key = "%s"
53+
title = "%[1]s"
54+
key = "%[2]s"
6155
}
62-
`, randomID, testKey)
56+
`, name, testKey)
6357

6458
check := resource.ComposeTestCheckFunc(
6559
resource.TestCheckResourceAttrSet("github_user_ssh_key.test", "title"),
@@ -87,6 +81,5 @@ func TestAccGithubUserSshKey(t *testing.T) {
8781
func newTestKey() string {
8882
privateKey, _ := rsa.GenerateKey(rand.Reader, 1024)
8983
publicKey, _ := ssh.NewPublicKey(&privateKey.PublicKey)
90-
testKey := strings.TrimRight(string(ssh.MarshalAuthorizedKey(publicKey)), "\n")
91-
return testKey
84+
return strings.TrimRight(string(ssh.MarshalAuthorizedKey(publicKey)), "\n")
9285
}

0 commit comments

Comments
 (0)