Repository navigation
fix: sweep expired token files and document uninstalling - #151
Merged
Merged
Conversation
Without a usable OS keyring, c1i caches one access-token file per set of credentials, so a token minted from credentials since replaced or removed stayed on disk forever. After a token file is written, delete the other token files there that no load would serve, and temp files over a minute old. Only regular files named as this package names them are touched, and the sweep keeps the cache's existing trust checks. Add a README section listing what c1i leaves behind on uninstall. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Logout removes only one tenant's credentials and its current token, and c1i can't list keyring entries, so the Uninstalling section now gives the macOS, Linux and Windows steps that remove the rest by hand. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # CHANGELOG.md
hex.DecodeString accepts uppercase, so a user file with an uppercase hex name could be swept; cacheKey only writes lowercase. Cover loose perms, oversized files and a token-named symlink in the sweep test, and list the c1i/<name> service older releases used for a *.conductor.one tenant. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With C1I_CLIENT_ID/C1I_CLIENT_SECRET set, logout resolves those instead, so it drops their cached token and leaves the keyring credentials' one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Near-miss names (short or truncated keys, a temp name without its leading dot or marker) now must survive the sweep, and the oversized fixture is valid JSON so only the 64 KiB bound rejects it. The README says logout still removes stored credentials when the env vars are set, covers the legacy name on Windows, and lists every file the sweep deletes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Without a usable OS keyring, c1i caches one access-token file per set of credentials under
<UserConfigDir>/c1i/tokens/. The file is named by a hash of host, client id and secret. When credentials are replaced or removed, their token file stays on disk forever. #150 stopped leftovers piling up in~/.c1i/cache/. This PR applies the same idea to the token cache, and documents what an uninstall leaves behind.A
c1i cleancommand was ruled out. go-keyring can't enumerate keyring entries and c1i keeps no list of tenants, so such a command couldn't truthfully claim to remove everything.What
Token file sweep (
internal/tokensource/cache.go): after a token file is renamed into place,pruneTokenDirdeletes the other files intokens/that no load would serve..tmp-files older than one minute are deleted. Younger ones are kept, so a concurrent write isn't broken..json, or the matching.<key>.json.tmp-*. A user'sbackup.json, an uppercase-hex name, a directory or a symlink is never touched.trustedCacheDirontokens/and itsc1iparent, plusLstat. The read path is now shared withloadFileCachedTokenthroughreadCachedTokenFile. The sweep only readstokens/and nevercredentials/.README "Uninstalling" lists what c1i leaves behind:
~/.c1i/~/.c1i.yaml<UserConfigDir>/c1i/(credentials and tokens)c1i/<host>, the legacyc1i/<name>, andcom.conductorone.c1i.tokensIt explains that
c1i auth logout --url <tenant>, once per tenant before removing the binary and withC1I_CLIENT_ID/C1I_CLIENT_SECRETunset, is the only way c1i can remove keyring credentials. It gives the manual removal steps for macOS (security delete-generic-password), Linux (secret-tool clear) and Windows (Credential Manager). It also notes that~/.sigstore/root/is shared with other Sigstore tools.cmd/agents.mdis unchanged, because agents don't uninstall c1i.CHANGELOG: one entry. With main merged in,
[Unreleased]also carries the entries for #148, #149 and #150. I checked each against its PR's diff.Verification
Tests:
TestStoreSweepsExpiredTokenFilesdrives the sweep throughstoreCachedToken. It checks that removed files are gone and that kept files survive..json.tmp-marker or the marker's dash, and user files).TestStoreSweepKeepsTokenJustWritten,TestStoreSweepLeavesCredentialsDir, andTestTokenSweepSkipsSymlinkedDir, which covers a symlinkedtokens/and a symlinkedc1i/.Mutation testing: with the sweep reverted to a no-op, the removal test fails.
credentials/.Live sweep: a built binary ran against a lab tenant on Linux, using the file cache. Fixtures were seeded into the real
tokens/dir, and one mint was forced by removing the current token file.credentials/did not change. The fixtures were removed afterwards.Linux keyring commands, tested live: gnome-keyring on a private D-Bus session with a throwaway HOME. Entries were written through go-keyring v0.2.8 under c1i's service and account names.
secret-tool clear service …removed both credential entries and both cached tokens, and an unrelated app's entry survived.macOS and Windows steps, not run: there's no Mac or Windows machine available. They come from go-keyring v0.2.8's source: its macOS
DeleteAllloops the samesecurity delete-generic-password -scall, and its Windows target names are<service>:<account>.Gates (
GOTOOLCHAIN=go1.27.2, atd47fa8c), all passing:go build,go vet,go test,go test -count=1 -shuffle=ongolangci-lint,go mod tidydiff,gosec,gitleaksgovulncheckfor linux, darwin and windows: no vulnerabilities.Dependency scan: no outdated direct dependency, and every workflow action and
go installpin is at its latest release.Adversarial review: independent reviewers covered six axes:
Each fix round was re-reviewed and approved. No blocking findings remain.
Known trade-offs
🤖 Generated with Claude Code