Problem
RefreshAgentToken (agenttoken.go:256) is an exported method on AgentTokenService that validates an existing agent token and issues a new one. It has zero production callers today.
It mints a credential row with NULL entitled_secret_keys, creating a trap for any future caller:
-
No entitled keys recorded. GenerateAgentTokenWithExpiry (the underlying generator) builds the AgentCredential struct without EntitledSecretKeys (agenttoken.go:323-329), and CreateAgentCredential omits SetEntitledSecretKeys (credential_store.go:55-60). The column stays NULL.
-
No JTI hash returned. GenerateAgentTokenWithExpiry returns (string, time.Time, error) — token and expiry, but no JTI hash. Compare GenerateAgentToken (agenttoken.go:162) which returns (string, string, error) — token and JTI hash. A future caller of RefreshAgentToken cannot record entitled keys even knowing they should, because they lack the hash needed to update the credential row. They will have a working token, a credential that looks fine, and a wall. They will not conclude "change this signature" — they will conclude recording happens elsewhere or is not needed here.
This is not a live defect today because nothing reads entitled_secret_keys yet. PR #1332 added the schema and PRs #1333/#1336 wire the recording. The fetch endpoint (PR 4, not yet dispatched) is the moment this becomes dangerous — it will check the stored entitled list, and a NULL list from a RefreshAgentToken-minted credential would fail closed (by design), but the trap is that the function looks correct and the failure mode is invisible until an operator reports it.
Resolution
Delete RefreshAgentToken and GenerateAgentTokenWithExpiry. Both are dead code:
RefreshAgentToken: zero callers outside tests (searched cmd/, internal/, all pkg/ packages)
GenerateAgentTokenWithExpiry: only caller is RefreshAgentToken and one test
Also delete the CredentialChecker interface and SetCredentialChecker, which exist solely for RefreshAgentToken's revocation check. The auth middleware (auth.go:157-168) performs the same revocation check independently.
Clean up the SetCredentialChecker wiring in server.go:1063 and the comment at server.go:1060.
The live token refresh path is handleAgentTokenRefresh (handlers_agents_core.go:2736), which uses GenerateAgentToken (with JTI hash return) and already records entitled keys as of PR #1336.
Related
Problem
RefreshAgentToken(agenttoken.go:256) is an exported method onAgentTokenServicethat validates an existing agent token and issues a new one. It has zero production callers today.It mints a credential row with NULL
entitled_secret_keys, creating a trap for any future caller:No entitled keys recorded.
GenerateAgentTokenWithExpiry(the underlying generator) builds theAgentCredentialstruct withoutEntitledSecretKeys(agenttoken.go:323-329), andCreateAgentCredentialomitsSetEntitledSecretKeys(credential_store.go:55-60). The column stays NULL.No JTI hash returned.
GenerateAgentTokenWithExpiryreturns(string, time.Time, error)— token and expiry, but no JTI hash. CompareGenerateAgentToken(agenttoken.go:162) which returns(string, string, error)— token and JTI hash. A future caller ofRefreshAgentTokencannot record entitled keys even knowing they should, because they lack the hash needed to update the credential row. They will have a working token, a credential that looks fine, and a wall. They will not conclude "change this signature" — they will conclude recording happens elsewhere or is not needed here.This is not a live defect today because nothing reads
entitled_secret_keysyet. PR #1332 added the schema and PRs #1333/#1336 wire the recording. The fetch endpoint (PR 4, not yet dispatched) is the moment this becomes dangerous — it will check the stored entitled list, and a NULL list from aRefreshAgentToken-minted credential would fail closed (by design), but the trap is that the function looks correct and the failure mode is invisible until an operator reports it.Resolution
Delete
RefreshAgentTokenandGenerateAgentTokenWithExpiry. Both are dead code:RefreshAgentToken: zero callers outside tests (searchedcmd/,internal/, allpkg/packages)GenerateAgentTokenWithExpiry: only caller isRefreshAgentTokenand one testAlso delete the
CredentialCheckerinterface andSetCredentialChecker, which exist solely forRefreshAgentToken's revocation check. The auth middleware (auth.go:157-168) performs the same revocation check independently.Clean up the
SetCredentialCheckerwiring inserver.go:1063and the comment atserver.go:1060.The live token refresh path is
handleAgentTokenRefresh(handlers_agents_core.go:2736), which usesGenerateAgentToken(with JTI hash return) and already records entitled keys as of PR #1336.Related
entitled_secret_keysonAgentCredentialresolveAgentSecrets, return JTI hash