cmd/auth.go::authStatusCmd reports the cache state with a bare os.Stat:
if p := exporter.SessionCachePath(); p != "" {
if _, err := os.Stat(p); err == nil {
cacheState = "session cached"
} else {
cacheState = "no session cached"
}
}
But exporter.loadCachedSession(user) — the function the export commands actually call to load the cache — performs four additional checks the status command skips:
- JSON parses
Version == cacheSchemaVersion (so a stale-schema cache from an old binary doesn't get used)
Username == user (so switching CRONOMETER_USERNAME invalidates the cache)
AuthToken != "" (so a zero/truncated file is rejected)
Any cache that passes os.Stat but fails one of those four is reported by auth status as session cached — and then the very next crono-export nutrition call silently re-logs in because the load actually fails. The status message lies.
The contract §5 expects auth status to be a useful readiness signal ("logged in as you@example.com (token expires 2026-05-01)" / "missing CRONOMETER_PASSWORD"). "I see a file at the path" doesn't clear that bar.
Easy fix
Swap the os.Stat for a call to loadCachedSession. The function already exists and does exactly the right validation; only thing it needs is to become exported (or a thin wrapper). Then the three branches become:
(valid cached session) — file present, parses, version + user + token all good
(no usable cached session) — file absent, or present-but-rejected
(cache disabled (CRONOMETER_NO_CACHE set)) — unchanged
No network call, so still satisfies the "local-only" promise.
Also stale
The command's Long description still claims:
This is a local check — no network call. It only verifies the
CRONOMETER_USERNAME and CRONOMETER_PASSWORD environment variables are set.
The function now also checks the cache path. Update the Long to match.
Severity: minor (correctness of an advisory subcommand)
cmd/auth.go::authStatusCmdreports the cache state with a bareos.Stat:But
exporter.loadCachedSession(user)— the function the export commands actually call to load the cache — performs four additional checks the status command skips:Version == cacheSchemaVersion(so a stale-schema cache from an old binary doesn't get used)Username == user(so switchingCRONOMETER_USERNAMEinvalidates the cache)AuthToken != ""(so a zero/truncated file is rejected)Any cache that passes
os.Statbut fails one of those four is reported byauth statusassession cached— and then the very nextcrono-export nutritioncall silently re-logs in because the load actually fails. The status message lies.The contract §5 expects
auth statusto be a useful readiness signal ("logged in as you@example.com (token expires 2026-05-01)" / "missing CRONOMETER_PASSWORD"). "I see a file at the path" doesn't clear that bar.Easy fix
Swap the
os.Statfor a call toloadCachedSession. The function already exists and does exactly the right validation; only thing it needs is to become exported (or a thin wrapper). Then the three branches become:(valid cached session)— file present, parses, version + user + token all good(no usable cached session)— file absent, or present-but-rejected(cache disabled (CRONOMETER_NO_CACHE set))— unchangedNo network call, so still satisfies the "local-only" promise.
Also stale
The command's
Longdescription still claims:The function now also checks the cache path. Update the Long to match.
Severity: minor (correctness of an advisory subcommand)