feat(api-proxy): add allow/deny model policy to apiProxy config#4406
feat(api-proxy): add allow/deny model policy to apiProxy config#4406Copilot wants to merge 4 commits into
Conversation
|
| Metric | Base | PR | Delta |
|---|---|---|---|
| Lines | 96.61% | 96.51% | 📉 -0.10% |
| Statements | 96.51% | 96.40% | 📉 -0.11% |
| Functions | 98.70% | 98.16% | 📉 -0.54% |
| Branches | 91.03% | 90.69% | 📉 -0.34% |
📁 Per-file Coverage Changes (2 files)
| File | Lines (Before → After) | Statements (Before → After) |
|---|---|---|
src/commands/validators/log-and-limits.ts |
90.3% → 82.7% (-7.66%) | 90.3% → 81.8% (-8.51%) |
src/config-writer.ts |
89.3% → 90.9% (+1.65%) | 89.3% → 90.9% (+1.65%) |
Coverage comparison generated by scripts/ci/compare-coverage.ts
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
@copilot fix failing checks, also add test agentic workflow(s) |
Looked at the failing checks:
For the test agentic workflow(s) ask — could you clarify what you'd like to see?
Which would you prefer (or both)? |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Done in 5a0f7f9.
|
|
| Metric | Base | PR | Delta |
|---|---|---|---|
| Lines | 96.61% | 96.56% | 📉 -0.05% |
| Statements | 96.51% | 96.47% | 📉 -0.04% |
| Functions | 98.70% | 98.73% | 📈 +0.03% |
| Branches | 91.03% | 90.64% | 📉 -0.39% |
📁 Per-file Coverage Changes (4 files)
| File | Lines (Before → After) | Statements (Before → After) |
|---|---|---|
src/commands/build-config.ts |
100.0% → 92.8% (-7.15%) | 100.0% → 92.8% (-7.15%) |
src/commands/main-action.ts |
95.5% → 95.6% (+0.13%) | 95.5% → 95.6% (+0.13%) |
src/config-writer.ts |
89.3% → 90.9% (+1.65%) | 89.3% → 90.9% (+1.65%) |
src/commands/validators/log-and-limits.ts |
90.3% → 92.0% (+1.68%) | 90.3% → 92.2% (+1.88%) |
✨ New Files (1 files)
src/dind-bootstrap.ts: 88.5% lines
Coverage comparison generated by scripts/ci/compare-coverage.ts
Claude Engine Smoke Test
Total: PASS
|
|
Smoke Test: API Proxy Model Allow/Deny Policy ✅ PASS
|
|
Smoke Test: Copilot BYOK (Direct) — PASS ✅ Running in direct BYOK mode (
Overall: PASS. cc author
|
🔬 Smoke Test Results — PASS
Overall: PASS | PR by
|
|
feat(api-proxy): add allow/deny model policy to apiProxy config Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "registry.npmjs.org"See Network Configuration for more information.
|
🔭 Smoke Test: API Proxy OpenTelemetry Tracing
All 5 scenarios pass. ✅
|
Chroot Version Comparison Results
Overall: ❌ Not all tests passed. Go versions match, but Python and Node.js differ between host and chroot environments.
|
🏗️ Build Test Suite Results
Overall: 8/8 ecosystems passed — ✅ PASS
|
Smoke Test Results
Overall status: FAIL Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "localhost"See Network Configuration for more information.
|
Smoke Test: GitHub Actions Services Connectivity
Overall: FAIL — Neither Redis nor PostgreSQL are reachable via
|
|
Running in direct BYOK mode (COPILOT_PROVIDER_API_KEY + COPILOT_PROVIDER_BASE_URL) via api-proxy → Azure OpenAI (Foundry, o4-mini-aw)
|
Adds
apiProxy.allowedModelsandapiProxy.disallowedModelsto the AWF config — provider-scoped glob lists that gate which models the api-proxy will resolve and serve. Patterns follow the gh-aw model-alias spec (provider/modelglob,*/glob, or bareglob). Denylist wins; non-empty allowlist requires a match; both empty = allow all.{ "apiProxy": { "allowedModels": ["copilot/gpt-*", "copilot/claude-sonnet-*"], "disallowedModels": ["*/claude-opus-*", "copilot/o1-*"] } }Enforcement
Alias resolution —
resolveModel,selectMiddlePowerFallback, andfilterResolvableAliasesfilter candidates through the policy, so blocked models can't sneak in via aliases or middle-power fallback, and/reflecthides aliases that resolve only to blocked models.Inference requests —
rewriteModelInBodyre-checks the resolved model and returns a blocked sentinel;composeBodyTransformsshort-circuits the chain andproxy-request.jsresponds403 model_blocked_by_policy:{ "error": { "type": "model_blocked_by_policy", "message": "Model 'claude-opus-4' is blocked by AWF policy", "provider": "copilot", "model": "claude-opus-4", "reason": "disallowed" } }Plumbing
docs/awf-config.schema.json, regeneratedsrc/awf-config-schema.json),AwfFileConfigmapping,ApiProxyOptions,LogAndLimitsResultvalidation, andWrapperConfigthreading.api-proxy-service-config.tsforwardsAWF_ALLOWED_MODELS/AWF_DISALLOWED_MODELS(JSON-encodedstring[]) to the sidecar;model-config.jsparses them into a frozenMODEL_POLICYand activates the body transform whenever aliases or policy are set.Docs
docs/awf-config-spec.mdplus CLI-mapping entries.Tests
model-resolver.test.jsforparseModelGlobList,matchProviderModelPattern,checkModelPolicy, policy-awareresolveModel, and blocked-request paths throughrewriteModelInBody.validate-options.test.tsfor thevalidateModelGlobListbranch ofsrc/commands/validators/log-and-limits.ts(invalid type, non-string entries, empty/whitespace trimming, happy path).Smoke workflow
.github/workflows/smoke-model-policy.md(Copilot engine, AWF sandbox) exercises the policy end-to-end: the agentcurls$COPILOT_API_URL/chat/completionswith a model matching the injected disallow pattern and asserts HTTP 403 +"type":"model_blocked_by_policy". A post-step also greps the api-proxy JSONL logs forblocked_modelentries as a secondary check.scripts/ci/postprocess-smoke-workflows.tsnow injectsapiProxy.allowedModels: ["*"]andapiProxy.disallowedModels: ["*/awf-smoke-blocked-test-model*"]into the inlineawf-config.jsonJSON emitted by the gh-aw compiler — scoped tosmoke-model-policy.lock.ymlonly and idempotent via a negative-lookahead regex. The disallow pattern is intentionally namespaced so it never collides with a real model and the agent's own model is unaffected.scripts/ci/postprocess-smoke-workflows.test.tscovering match, replacement, both idempotency branches, and a no-match guard.