diff --git a/provider/pkg/internal/pulumiapi/accesstokens.go b/provider/pkg/internal/pulumiapi/accesstokens.go index 7ed9753f..97b2c94b 100644 --- a/provider/pkg/internal/pulumiapi/accesstokens.go +++ b/provider/pkg/internal/pulumiapi/accesstokens.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, @@ -36,6 +36,16 @@ type createTokenRequest struct { Description string `json:"description"` } +type accessTokenResponse struct { + ID string `json:"id"` + Description string `json:"description"` + LastUsed int `json:"lastUsed"` +} + +type listTokenResponse struct { + Tokens []accessTokenResponse `json:"tokens"` +} + func (c *Client) CreateAccessToken(ctx context.Context, description string) (*AccessToken, error) { apiPath := path.Join("user", "tokens") @@ -73,3 +83,27 @@ func (c *Client) DeleteAccessToken(ctx context.Context, tokenId string) error { return nil } + +func (c *Client) GetAccessToken(ctx context.Context, id string) (*AccessToken, error) { + apiPath := path.Join("user", "tokens") + + var listRes listTokenResponse + + _, err := c.do(ctx, http.MethodGet, apiPath, nil, &listRes) + + if err != nil { + return nil, fmt.Errorf("failed to list access tokens: %w", err) + } + + for i := 0; i < len(listRes.Tokens); i++ { + token := listRes.Tokens[i] + if token.ID == id { + return &AccessToken{ + ID: token.ID, + Description: token.Description, + }, nil + } + } + + return nil, nil +} diff --git a/provider/pkg/internal/pulumiapi/accesstokens_test.go b/provider/pkg/internal/pulumiapi/accesstokens_test.go index 0644658b..f4598983 100644 --- a/provider/pkg/internal/pulumiapi/accesstokens_test.go +++ b/provider/pkg/internal/pulumiapi/accesstokens_test.go @@ -89,3 +89,59 @@ func TestCreateAccessToken(t *testing.T) { ) }) } + +func TestGetAccessToken(t *testing.T) { + id := "uuid" + desc := "token description" + lastUsed := 123 + t.Run("Happy Path", func(t *testing.T) { + resp := listTokenResponse{ + Tokens: []accessTokenResponse{ + accessTokenResponse{ + ID: id, + Description: desc, + LastUsed: lastUsed, + }, + accessTokenResponse{ + ID: "other", + Description: desc, + LastUsed: lastUsed, + }, + }, + } + c, cleanup := startTestServer(t, testServerConfig{ + ExpectedReqMethod: http.MethodGet, + ExpectedReqBody: nil, + ExpectedReqPath: "/api/user/tokens", + ResponseCode: 200, + ResponseBody: resp, + }) + defer cleanup() + token, err := c.GetAccessToken(ctx, id) + assert.NoError(t, err) + assert.Equal(t, &AccessToken{ + ID: id, + Description: desc, + }, token) + }) + + t.Run("Error", func(t *testing.T) { + c, cleanup := startTestServer(t, testServerConfig{ + ExpectedReqMethod: http.MethodGet, + ExpectedReqPath: "/api/user/tokens", + ExpectedReqBody: nil, + ResponseCode: 401, + ResponseBody: errorResponse{ + StatusCode: 401, + Message: "unauthorized", + }, + }) + defer cleanup() + token, err := c.GetAccessToken(ctx, id) + assert.Nil(t, token, "token should be nil") + assert.EqualError(t, + err, + `failed to list access tokens: 401 API error: unauthorized`, + ) + }) +} diff --git a/provider/pkg/provider/access_token.go b/provider/pkg/provider/access_token.go index c833bdb1..5e3c7891 100644 --- a/provider/pkg/provider/access_token.go +++ b/provider/pkg/provider/access_token.go @@ -119,7 +119,21 @@ func (at *PulumiServiceAccessTokenResource) Update(req *pulumirpc.UpdateRequest) } func (at *PulumiServiceAccessTokenResource) Read(req *pulumirpc.ReadRequest) (*pulumirpc.ReadResponse, error) { - return &pulumirpc.ReadResponse{}, nil + ctx := context.Background() + + // the access token is immutable; if we get nil it got deleted, otherwise all data is the same + accesstoken, err := at.getAccessToken(ctx, req.GetId()) + if err != nil { + return nil, err + } + if accesstoken == nil { + return &pulumirpc.ReadResponse{}, nil + } + + return &pulumirpc.ReadResponse{ + Id: req.GetId(), + Properties: req.GetProperties(), + }, nil } func (at *PulumiServiceAccessTokenResource) Invoke(s *pulumiserviceProvider, req *pulumirpc.InvokeRequest) (*pulumirpc.InvokeResponse, error) { @@ -142,3 +156,12 @@ func (at *PulumiServiceAccessTokenResource) createAccessToken(ctx context.Contex func (at *PulumiServiceAccessTokenResource) deleteAccessToken(ctx context.Context, tokenId string) error { return at.client.DeleteAccessToken(ctx, tokenId) } + +func (at *PulumiServiceAccessTokenResource) getAccessToken(ctx context.Context, id string) (*pulumiapi.AccessToken, error) { + accesstoken, err := at.client.GetAccessToken(ctx, id) + if err != nil { + return nil, err + } + + return accesstoken, nil +}