feat(join-tokens): [44794] API changes for managing GitHub Join Tokens#54374
Conversation
nicholasmarais1158
left a comment
There was a problem hiding this comment.
A few questions.
| if r.Method == "PUT" { | ||
| // if using the PUT route, tokenId will be present | ||
| // in the X-Teleport-TokenName header | ||
| tokenId = r.Header.Get(HeaderTokenName) |
There was a problem hiding this comment.
Is this a current pattern, or something legacy?
There was a problem hiding this comment.
I'm not sure - it strikes me as a little odd - @avatus may have more context?
There was a problem hiding this comment.
we added it here specifically so someone could not get the secret token name from the request param in logs as JoinTokens are meant to be secret
There was a problem hiding this comment.
Thanks for the context @avatus.
It makes sense for the delete endpoint, given the id is included in the path, but this endpoint doesn't use path params (POST|PUT /webapi/tokens).
Currently the Web UI doesn't use the PUT endpoint, should the header approach be retained or should we use a value from the request body instead?
| // If this is an edit, then overwrite the metadata to retain the existing fields | ||
| if existingToken != nil { | ||
| token.SetMetadata(existingToken.GetMetadata()) |
There was a problem hiding this comment.
Is this a valid operation to perform? Is it safe to copy the metadata unchanged to the new token? Does it mess with the revision mechanism?
There was a problem hiding this comment.
Yeah - that's fine. The revision mechanism is actually designed to be used this way. When performing an action and providing the revision, the backend checks that the provided revision matches what is currently in the backend. You have introduced a change in behaviour here (e.g it'll now perform optimistic locking, which it didn't perform previously as the revision was wiped) but this is probably a good thing since it'll reject edits where the resource has changed since it was fetched.
There was a problem hiding this comment.
I wouldn't expect the revision to matter much if we are still calling UpsertToken below though.
There was a problem hiding this comment.
I wouldn't expect the revision to matter much if we are still calling UpsertToken below though.
Yeah - imho, we should eventually split this webapi endpoint to a seperate create/update and call the appropriate underlying Create or Update. At the moment, you can accidentally overwrite an existing token when creating a new one. But I think that's best left out of scope for this PR.
| // Skip enterprise-only methods | ||
| if method == types.JoinMethodTPM || method == types.JoinMethodSpacelift { | ||
| t.Skipf("Skipping %s, as it's enterprise-only", method) | ||
| } |
There was a problem hiding this comment.
Is there an enterprise-mode that can be used to prevent having to skip enterprise-only features?
There was a problem hiding this comment.
An error is returned when creating TMP and Spacelift tokens.
There was a problem hiding this comment.
You can do something similar to:
modules.SetTestModules(t, &modules.TestModules{
TestBuildType: modules.BuildEnterprise,
TestFeatures: modules.Features{
Cloud: true,
},
}But since this modifies global state, it means that the test can't be marked parallel.
strideynet
left a comment
There was a problem hiding this comment.
I think this is nearly there - I've identified a few nits but I'm also waiting for some more context before approving.
| } | ||
| } | ||
|
|
||
| func TestGetGithubTokens(t *testing.T) { |
There was a problem hiding this comment.
Would it be possible to extend the existing TestGetTokens test table rather than introduce a new test here?
| // Skip enterprise-only methods | ||
| if method == types.JoinMethodTPM || method == types.JoinMethodSpacelift { | ||
| t.Skipf("Skipping %s, as it's enterprise-only", method) | ||
| } |
There was a problem hiding this comment.
You can do something similar to:
modules.SetTestModules(t, &modules.TestModules{
TestBuildType: modules.BuildEnterprise,
TestFeatures: modules.Features{
Cloud: true,
},
}But since this modifies global state, it means that the test can't be marked parallel.
|
|
||
| if editing && tokenId != req.Name { | ||
| return nil, trace.BadParameter("renaming tokens is not supported") | ||
| var tokenId string |
There was a problem hiding this comment.
Nit: I'd simplify this by removing the else branch and initialising the variable with the value we'd set in the else.
| require.Equal(t, map[string]string{ | ||
| "test-key": "test-value", | ||
| }, editedToken.GetMetadata().Labels) | ||
| } |
| } | ||
|
|
||
| var existingToken types.ProvisionToken | ||
| if tokenId != "" { |
There was a problem hiding this comment.
I have a hunch that by this point, we definitely have a value for tokenId, so we can omit this if statement.
There was a problem hiding this comment.
Reverted in f0254a6. If req.Name is empty we want to avoid fetching an existing token.
|
will the updates to this endpoint support web UIs of version n-1 making this request still? for example, if this goes out in 17.5, will a webUI served by 17.4 fail when making this request to a 17.5 proxy? |
@avatus Yes, it's backwards compatible. Out of interest, given the Proxy serves the Web UI, how would the situation of an older Web UI and new Proxy come about? |
wonderful question. There are many users that do rolling upgrades on their clusters. For example, if i have 4 proxies and i upgrade 2 of them to N+1, if a user gets served the web UI from proxy N, their requests during their session lifetime may get routed to a proxy N api, or proxy N+1. Its an edge case, but not as edge-y as it may sound. Sometimes, its unavoidable, but we want to keep it top of mind when we can to make sure as many features work between new/old proxy and new/old web UI. You can read a bit more about it here |
|
@nicholasmarais1158 See the table below for backport results.
|
#54374) * Return github-specific config from `GET /webapi/tokens` * Support "token" in `/webapi/yaml/parse/:kind` * Use empty time.Time for token expiry (`POST /webapi/tokens`) * Cover enterprise token types in tests * Cover github tokens in existing tests * Tweak handling of `tokenId` * Check expiry is not overwritten * Revert removing tokenId check * Remove use of `X-Teleport-TokenName` header # Conflicts: # lib/web/join_tokens.go # lib/web/join_tokens_test.go # lib/web/yaml.go
…54454) * feat(join-tokens): [44794] API changes for managing GitHub Join Tokens (#54374) * Return github-specific config from `GET /webapi/tokens` * Support "token" in `/webapi/yaml/parse/:kind` * Use empty time.Time for token expiry (`POST /webapi/tokens`) * Cover enterprise token types in tests * Cover github tokens in existing tests * Tweak handling of `tokenId` * Check expiry is not overwritten * Revert removing tokenId check * Remove use of `X-Teleport-TokenName` header # Conflicts: # lib/web/join_tokens.go # lib/web/join_tokens_test.go # lib/web/yaml.go * nit: Fix comment
Description
This change prepares the Web API to support creating and editing GitHub Join Tokens from the Join Tokens page.
Issue: #44794
changelog: Fixed an issue causing Join Token expiries to be overwritten when editing a token
Changes
GET /webapi/tokens- this is required to populate the edit form/webapi/yaml/parse/:kind- this is required to allow detection of unsupported fieldsPOST /webapi/tokens- also fixes a bug related to the expiry being overwritten on edit