Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion docs/src/content/docs/enterprise/security.md
Original file line number Diff line number Diff line change
Expand Up @@ -565,9 +565,40 @@ For an org standardizing on APM:
- Publish an `apm-policy.yml` from your `<org>/.github` repo with an allow list and an MCP transport restriction. See [Governance Guide](../governance-guide/).
- Require signed commits on the source repos APM pulls from -- this is where the trust chain bottoms out.
- Route dep traffic through an enterprise proxy with audit logging. See [Registry Proxy & Air-gapped](../registry-proxy/).
- Forbid `allow_insecure: true` via the policy allow list, except where an air-gapped mirror demands it.
- Treat insecure transport as a separate CI control. `apm-policy.yml` has no
dedicated `allow_insecure` field: `dependencies.allow` and
`dependencies.deny` match scheme-blind canonical package identities. The
default `github.com` host is omitted while non-default hosts are retained, so
rules can restrict package and host identity but cannot distinguish
`http://` from `https://` for the same canonical host and path. Reject committed
`allow_insecure: true` entries and prohibit `--allow-insecure` and
`--allow-insecure-host` in standard CI; review both explicit gates for any
air-gapped exception. `registry_source.allow_non_registry` is a separate
source-routing control, not an insecure-transport setting.
- Scan committed `apm.yml` for literal secrets in `mcp.env` values -- APM assumes env-var indirection (`GITHUB_TOKEN: ${GITHUB_TOKEN}`) but does not enforce it. `apm install` auto-adds `apm_modules/` to `.gitignore`, keeping cached source trees out of commits.

A restrictive dependency policy is still valuable, but it is identity-based,
not transport-aware:

```yaml
# apm-policy.yml
name: contoso-security
version: "1.0"
enforcement: block

dependencies:
allow:
- "contoso/approved-agent-config"
- "microsoft/*"
```

This example blocks every unlisted package identity regardless of transport; it
does **not** enforce HTTPS for the two allowed patterns. See the
[HTTP dependency two-gate model](#http-insecure-dependencies),
[dependency pattern matching](../policy-reference/#pattern-matching), and the
[`registry_source` policy](../../reference/policy-schema/#registry_source) for
the three distinct controls.

## Frequently asked questions

### Can a package embed hidden instructions?
Expand Down
16 changes: 16 additions & 0 deletions tests/unit/test_tls_docs_scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,22 @@ def test_enterprise_security_docs_transport_trust_model():
assert "Rust" in security


def test_enterprise_security_docs_do_not_claim_transport_aware_policy():
security = (
_repo_root() / "docs" / "src" / "content" / "docs" / "enterprise" / "security.md"
).read_text(encoding="utf-8")
# Keep this contract about the guidance rather than Markdown presentation.
normalized = " ".join(security.replace("**", "").split())

assert "no dedicated `allow_insecure` field" in normalized
assert "scheme-blind canonical package identities" in normalized
assert "non-default hosts are retained" in normalized
assert "host-blind" not in normalized
assert "does not enforce HTTPS" in normalized
assert "`registry_source.allow_non_registry`" in normalized
assert "Forbid `allow_insecure: true` via the policy allow list" not in normalized


def test_ssl_docs_verify_apm_path_and_mark_planned_scope():
docs = (
_repo_root() / "docs" / "src" / "content" / "docs" / "troubleshooting" / "ssl-issues.md"
Expand Down