Repository navigation
fix: a workspace value has one source; an empty delivered file is broken (r144) - #90
Merged
Merged
Conversation
…ken (r144) Three refusals under the maximum-security posture, from review r144: - f1: WorkspaceValue and WorkspaceValueIfSet now report a pinned value whose live delivery breaks as ErrAuthorityValueChanged wrapping the reason, as Authority.Recheck already did. #88 returned the bare read failure, so a caller that stops or re-seals on that sentinel missed it. - f2: a file carrier naming an empty file is refused with ErrFileCarrier ("delivered file is empty"), like a missing file. Codefly delivers by file only above resources.FileCarrierThreshold, so an empty file is a truncated write or a mount race. It used to read as absent, which let WorkspaceValue and ReadAuthority answer from the secret namespace (r144's "sec1" probe). The check sits in readFileCarrier, so every accessor and LoadEnvironmentVariables refuse it. - f3: a name carried in both the public and the secret namespace is refused with the new ErrWorkspaceValueInBothNamespaces: two sources for one value, like inline plus file. It used to answer from the public one silently (r144's "pub" probe), so a stale public copy left behind after a move to the secret namespace kept answering. WorkspaceConfiguration and WorkspaceSecret, which each name one namespace, still answer. Each test fails with its fix reverted. The README gains a Workspace values section; AGENTS.md, the carrier skill and configuration-documents.md say an empty delivered file is broken, not absent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 26, 2026
antoinetoussaint-byte
added a commit
that referenced
this pull request
Oct 26, 2026
release/0.4: backport #90 (a workspace value has one source; an empty delivered file is broken)
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.
Summary
Follow-up to #88, from review r144 (f1–f3), under the maximum-security posture. Every workspace value now has exactly one source, and every broken delivery is refused with a named reason.
f1: a pinned value's broken delivery is
ErrAuthorityValueChangedeverywhere.WorkspaceValueandWorkspaceValueIfSetnow wrap a live read failure for a pinned name asErrAuthorityValueChanged: <name> cannot be read: <cause>, which is howAuthority.Recheckalready reports it. #88 returned the bareErrFileCarrier, so a caller that stops or re-seals onErrAuthorityValueChangedmissed a broken pinned delivery. Before #88, the base returnedErrAuthorityValueChangedwithout the cause. Both are now one helper,pinnedReadFailure.f2: an empty delivered file is a broken delivery, never absence.
readFileCarrierrefuses a file carrier whose file is empty withErrFileCarrier: <key>: delivered file is empty. Core delivers a value by file only when it exceedsresources.FileCarrierThreshold(deliverByFile), so an empty file is a truncated write or a mount race. It used to read as absent, soWorkspaceValueandReadAuthorityanswered from the secret namespace: r144 probed an empty public file plus a secretsec1and got"sec1"with a nil error. The check sits in the one function that reads carrier files, so every accessor andLoadEnvironmentVariablesrefuse it. Configuration documents report it asErrConfigurationDocumentUnreadable. An empty inline value is still absent.f3: a name in both namespaces is refused.
workspaceValueIfSetLivereads both namespaces and refuses a name carried in both with the new exportedErrWorkspaceValueInBothNamespaces(<name>/<key>, never the value). That is two sources for one value, the same rule as inline plus file. It used to answer from the public namespace silently: r144 probed publicpubplus secretsecand got"pub". A deployment that moved a value to the secret namespace and left the old public copy behind kept answering the stale copy. A read failure in either namespace is returned. Only true absence moves the lookup on.WorkspaceConfigurationandWorkspaceSecreteach name one namespace and still answer it.Docs:
README.mdgains a Workspace values section, and the authority section names the f1 behaviour.AGENTS.md, the empty-value bullet now names the two refusals, within the 200-line budget (TestAgentContextRootStaysWithinItsBudget).runtime-carrier-accessorskill anddocs/configuration-documents.mdnow say an empty delivered file is broken, not absent.Fix or hack
Fix, at the owner. f1 and f3 change the single lookup #88 made for
WorkspaceValue,WorkspaceValueIfSet,ReadAuthorityandRecheck. f2 changes the single function that reads carrier files. Nothing new is added beside them.Behaviour change for callers
WorkspaceValue/WorkspaceValueIfSet/ReadAuthorityinstead of the public value. Remove one of the two copies.LoadEnvironmentVariables, the same as for a missing file.workspaceEnvhelpers, in auth-gatewayconfiguration.go:13and accountswork.go:2060, useerr == nil && value != ""and otherwise fall back toos.Getenv. Its testTestWorkspaceEnvResolvesConfigurationSecretAndFallback(auth-gatewayconfiguration_test.go:27-28) holds that fallback in place. accountswork.goalso discards the error outright at:2088,:2108,:2158and:2490(value, _ := ...WorkspaceValue(...)); lines are as of module-saas-starterde039b2. These call sites turn the refusals from fix: an unreadable public value is refused, never answered from the secret namespace (r139) #88 and this PR (an unreadable delivery, an empty delivered file, a name in both namespaces) back into a silent fallback to a process variable. The SDK refuses correctly; the fail-open is in the consumer and is the consumer's to fix. No issue has been filed.Test plan
TestAnUnreadablePublicValueIsNeverAnsweredFromTheSecretNamespacenow assertsErrAuthorityValueChangedplusErrFileCarrierfromWorkspaceValueandWorkspaceValueIfSeton a pinned name whose public delivery broke, with no value in the error. It fails with f1 reverted.TestAnEmptyDeliveredFileIsABrokenDeliveryreproduces r144'ssec1probe.WorkspaceConfiguration,WorkspaceValue,WorkspaceValueIfSetandReadAuthorityall refuse withErrFileCarrier, and so doesLoadEnvironmentVariables. The listing's empty-file subtest now expects a named failure. Both fail with f2 reverted.TestAValueInBothNamespacesIsRefusedreproduces r144'spubprobe.WorkspaceValue,WorkspaceValueIfSetandReadAuthorityrefuse withErrWorkspaceValueInBothNamespaces, while the per-namespace accessors still answer. A value pinned from one namespace whose name then appears in the other is refused byRecheckand byWorkspaceValueasErrAuthorityValueChanged. It fails with f3 reverted../scripts/check-one-implementation.sh: ok (86 files)../scripts/security-posture.sh: SP-WC-01, SP-WC-05 ok.go test -race -count=1 ./...passes in the root (including the agent-context budget) and inworkcontext.readFileCarrieris at 100%.golangci-lint run ./...: 0 issues in both modules.release/0.4
This goes to
release/0.4by cherry-pick once it merges, after #81's backport, which restores the retractions v0.4.2 lost.Not verified
🤖 Generated with Claude Code