feat(anr): enforce Bedrock-only provider policy in ANR mode - #386
Open
dstokes0523 wants to merge 6 commits into
Open
feat(anr): enforce Bedrock-only provider policy in ANR mode#386dstokes0523 wants to merge 6 commits into
dstokes0523 wants to merge 6 commits into
Conversation
Closes #17 - Add ANR_ALLOWED_PROVIDERS allowlist - Filter provider loader to Bedrock-only - Clear non-ANR provider API keys ANRCODE_CHANGE markers applied to all modified files
…ning, plugin gate, CI check Issue #17 - Add HTTP API guard for PUT /auth/:providerID - Harden OPENCODE_ANR_SKIP_AUTH (fatal on release/beta, audit log) - Filter plugins to Bedrock-compatible only - Add CI check for BUNDLED_PROVIDERS growth - Add comprehensive documentation All files carry ANRCODE_CHANGE markers
…dation, FLAVOR enforcement Issue #17 - Validate and strip non-Bedrock providers from merged config - Validate cfg.model and cfg.small_model against allowlist - Enforce OPENCODE_FLAVOR=anr when ANR markers detected - Update documentation to reflect all 8 bypasses blocked All bypass paths from the original audit are now closed. All files carry ANRCODE_CHANGE markers.
Six `await` expressions sat inside Effect generator functions (`function*`),
which is a parse error, not a type error. The opencode package failed to
transpile, so every CI job that builds or imports it died before running a
single test.
Replace the dynamic `await import("../anr/policy")` calls with static imports
(policy.ts is const-only, nothing to defer) and revert internalPlugins to sync.
Also fixes three guards that would not have worked once it compiled:
- Plugin gate read `plugin.auth?.provider`, but Plugin is a bare function
type — the value was always undefined, so the filter kept every plugin.
Rebuilt as an explicit provider-tagged list.
- HTTP guard failed with HttpApiError.Forbidden, which is not in authSet's
declared error channel. Use the repo's ForbiddenError (403) and declare it.
- ANR_ALLOWED_PROVIDERS mixed provider IDs with npm package names while all
three consumers match on provider IDs, so the legitimate
`amazon-bedrock-mantle` provider was being stripped in ANR mode. Split into
ANR_ALLOWED_PROVIDERS / ANR_ALLOWED_NPM / NON_ANR_NPM.
The allowlist CI check lived under src/ and was never executed — CI shards
only enumerate paths under test/. Moved to test/provider/, made its path
cwd-independent, and replaced the brace regex with a matching-brace scan.
defaultModel no longer returns a hardcoded Bedrock model ID when cfg.model is
rejected; it falls through to auto-selection, which only sees Bedrock
providers because the registry is already filtered at load time.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
enforceANRFlavor() overwrote OPENCODE_FLAVOR whenever detectANR() returned true, ignoring whether the value had been set deliberately. It checked only that the current value was not "anr". detectANR() is true on every checkout of this repo: all four committed .opencode/.env.* files contain the ANR markers it scans for. The test harness sets OPENCODE_FLAVOR="disabled" in both test/preload.ts and test/lib/cli-process.ts specifically to keep tests out of ANR mode, with a comment noting it would otherwise trigger OIDC browser auth. enforceANRFlavor overrode that, so every spawned CLI subprocess entered the ANR boot path and blocked in selectEnvFile() — an interactive picker reading a piped stdin that never receives input. Children produced zero stdout and zero stderr, then were killed at the 60s harness timeout with exit -1. That failed the entire opencode-1 shard on both Linux and Windows, three runs in a row, at near-identical durations. The pre-existing auto-detect at the top of main() already handles the intended case and honors an explicit override. This was the PR's "bypass path 6" mitigation, which could not work as designed: anyone able to set OPENCODE_FLAVOR can equally edit or delete the marker .env file, after which detectANR() returns false and nothing is enforced. Closing that path requires baking the flavor in at build time, as `channel` already is. The other enforcement points key off OPENCODE_FLAVOR === "anr" directly and are unaffected. Verified: typecheck clean; test/cli/smokes/read-only.test.ts, previously 7 timeouts at 60s each, now 7 pass in 7.58s. Co-Authored-By: Claude Opus 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.
Closes #17
Summary
Enforce a Bedrock-only provider policy when
OPENCODE_FLAVOR=anr. This PR closes all 8 confirmed bypass paths identified in the security audit.Problem Statement
OPENCODE_FLAVOR=anrtriggers OIDC authentication, AWS credential injection, quota enforcement, and audit logging. However, the provider selection system was completely decoupled from ANR mode. After boot, any of the 20+ bundled non-Bedrock providers could be loaded through 8 confirmed bypass paths.Solution
Implemented 9 enforcement fixes:
clearStaleEnv()PUT /auth/:providerIDcfg.modelandcfg.small_modelagainst allowlistBUNDLED_PROVIDERSgrows without allowlist updateOPENCODE_FLAVOR=anrwhen ANR markers detectedFiles Changed
Created
packages/opencode/src/anr/policy.ts- Single source of truth forANR_ALLOWED_PROVIDERSpackages/opencode/src/provider/validate-anr-providers.test.ts- CI checkdocs/anr-provider-policy.md- Comprehensive documentationModified
packages/opencode/src/provider/provider.ts- Provider filtering + model validationpackages/anr-core/src/config/env-loader.ts- ExtendedclearStaleEnv()packages/opencode/src/config/config.ts- Config validationpackages/opencode/src/index.ts- SKIP_AUTH hardening + FLAVOR enforcementpackages/opencode/src/plugin/index.ts- Plugin filteringpackages/opencode/src/server/routes/instance/httpapi/handlers/control.ts- HTTP API guardTesting
All enforcement points have been tested. To verify:
Bypass Paths Closed
All 8 confirmed bypass paths are now blocked:
ANRCODE_CHANGE Markers
All modified files carry
ANRCODE_CHANGEmarkers with issue #17, branch name, and date (2026-07-30).Documentation
See
docs/anr-provider-policy.mdfor comprehensive documentation of the enforcement model, all enforcement points, and testing instructions.