Skip to main content

subvectors

PyPI CI License: Apache-2.0 Python

Conformance vectors for OIDC trust subjects — the answer key for CI/CD OIDC trust decisions: a cited, versioned test-vector suite answering "does subject S satisfy trust condition C, and is C safe?"

When a CI pipeline authenticates to a cloud via OIDC (GitHub Actions to AWS/Azure/GCP today), the entire security boundary is a string comparison: the token's sub claim versus an admin-written matching rule — an AWS IAM trust-policy condition, an Azure federated-identity-credential (FIC) subject, a GCP Workload Identity Federation attribute condition. Every security tool in this space must re-implement that comparison and judge those rules. They re-figure it out alone, and they get it wrong.

Status: v0.7.0 on PyPI - the corpus ships inside the wheel. An independent personal project, built on personal time and personal equipment. Every vector is source-cited, and 16 of the 163 vectors are observed, all of them in the github-aws suite (56 vectors), by two methods: 11 against the live AWS IAM policy simulator (aws-iam-policy-simulator, iam:SimulateCustomPolicy, with five iam:CreateRole probes recorded behind one of them), and 5 against tokens a real GitHub Actions job minted on 2026-10-08 (github-actions-oidc-claims: the issuer side only - what GitHub puts in the token - with the AWS match of that string still documented). No token exchange has been observed yet, on AWS or on any other cloud - the simulator evaluates a trust policy against a claim value you hand it, and the GitHub probe mints a token nobody presents. Every other suite is documented only. Each observed vector links a committed transcript under observations/ holding the exact request and the verbatim response, so the claim is auditable without an AWS or GitHub account. The generated Coverage block carries the live documented/observed split.

The proof this is needed (verified 2026-07-04; charset claim re-checked against current source 2026-09-19)

Checkov — one of the most widely used IaC security scanners — ships the only Azure FIC subject check anywhere (CKV_AZURE_249). Read against its own source:

  • It PASSES repo:org/* (any repo in the org may assume the role) and repo:org/repo:pull_request (unreviewed PR code may) — dangerous patterns waved through.
  • Its repo regex has no @ in the charset, so it will FAIL every valid immutable-format subject (repo:owner@123456/name@456789:...) — the format GitHub makes mandatory for repos created after 2026-07-15 (observed on a repository created 2026-10-08: it minted that format with no opt-in).

It is a bug class, not one tool's slip: another scanner's OIDC guardrail shipped exactly the set-operator miss this corpus grades — ForAnyValue:StringLike hiding a wildcard sub — as CVE-2026-82856 (@hulumi/policies before 1.3.2, CVSS 9.3). And a third-party fixture repository reports that applying Checkov PR #7610 drops Checkov's immutable-subject false positives from 8 to 0, which is the same defect read from the other side.

The formats churn (GitHub immutable claims, Azure flexible-FIC expressions in preview, per-issuer dialects from GitLab/Bitbucket/CircleCI), and every scanner re-derives the semantics from prose docs. A single maintained, cited corpus of test vectors fixes that for everyone.

What a vector looks like

{
  "id": "gh-aws-0007",
  "issuer": "github",
  "subject": "repo:acme/webapp:pull_request",
  "condition": { "consumer": "aws-stringlike", "pattern": "repo:acme/webapp:*" },
  "expect": "match",
  "judgment": {
    "grade": "dangerous",
    "reason": "pattern admits pull_request runs, which execute unmerged proposed changes rather than the protected default branch"
  },
  "sources": ["https://docs.github.com/en/actions/deployment/security-hardening-your-deployments"],
  "status": "documented"
}

Three layers per vector:

  1. Grammar — is the subject well-formed for its issuer (classic AND immutable GitHub formats)?
  2. Match semantics — does it satisfy the consumer's condition (AWS StringLike/StringEquals globbing, Azure FIC exact match + flexible expressions, GCP CEL)?
  3. Judgment — is the condition safe? Graded findings for the patterns that matter: pull_request subjects, unprotected refs, wildcarded repos/orgs, missing aud pinning. The graded patterns are a stable, citable vocabulary — see docs/JUDGMENT-CATALOG.md.

Every vector carries a source citation and a provenance status — documented (derived from primary documentation) or observed (recorded from a live exchange). The current split is generated under Coverage rather than asserted here, so it cannot drift. A small, dependency-free Python reference matcher (pytest) passes the suite — it is a correctness oracle, not a product.

Coverage

14 suites - 163 vectors across 5 issuers and 6 consumer semantics.

Vectors by issuer x cloud-consumer semantics:

Issuer aws-stringlike aws-stringequals aws-all azure-fic-exact azure-fic-flexible gcp-cel Total
github 18 31 7 10 12 12 90
gitlab 5 5 6 6 6 6 34
bitbucket 1 2 3 - - - 6
circleci 4 - 4 - - 6 14
terraform-cloud 3 3 1 - 6 6 19
Total 31 41 21 16 24 30 163

Suites:

  • bitbucket-aws 0.1.0 - 6 vectors
  • circleci-aws 0.2.0 - 8 vectors
  • circleci-gcp 0.1.0 - 6 vectors
  • github-aws 0.9.0 - 56 vectors
  • github-azure-flexible 0.2.0 - 12 vectors
  • github-azure 0.1.0 - 10 vectors
  • github-gcp 0.1.1 - 12 vectors
  • gitlab-aws 0.2.0 - 16 vectors
  • gitlab-azure-flexible 0.2.0 - 6 vectors
  • gitlab-azure 0.1.0 - 6 vectors
  • gitlab-gcp 0.1.0 - 6 vectors
  • terraform-aws 0.1.0 - 7 vectors
  • terraform-azure-flexible 0.1.0 - 6 vectors
  • terraform-gcp 0.1.0 - 6 vectors

Judgments: 34 safe - 53 caution - 52 dangerous - 24 ungraded (mechanical no-match / contrast vectors carry no safety grade).

Provenance: 147 documented - 16 observed.

Install

pip install subvectors

The wheel ships the entire corpus, so a consumer pins a versioned artifact instead of vendoring JSON by hand:

from subvectors import corpus

corpus.suite_names()                 # ['bitbucket-aws', ..., 'terraform-gcp']
corpus.load_suite("github-aws")      # one suite, parsed
corpus.load_schema()                 # the JSON Schema the suites validate against

Prefer no dependency at all? The vectors are plain JSON under vectors/ — clone and read. The corpus itself is CC0 (vectors/LICENSE).

Why an answer key instead of another scanner

Scanners in this space compete and get obsoleted: SpecterOps GitHound already maps workflow-to-cloud OIDC reach, Prowler shipped a GitHub provider (2026-07-02), Wiz and Datadog are converging. A test-vector suite does not compete with scanners — it grades them. Each new tool entering the space is a new consumer of the corpus, the way Wycheproof tests everyone's cryptography and the JSON-Schema-Test-Suite tests everyone's validators. Consumers keep their own matching code (no runtime dependency to trust) and import the vectors at test time.

The intended distribution channel is upstream PRs against the tools the vectors grade — the channel and the proof in one. Four are open and none has been merged or reviewed by a maintainer (PR state checked 2026-10-08): Checkov #7610 (opened 2026-07-14), #7627 (2026-07-27) and #7665 (2026-08-31) against the OIDC check family, and Cartography #3088 (2026-07-30) for unparsed trust-policy conditions. Zero merged upstream PRs is the honest scoreboard; see ROADMAP.md.

Scope order

GitHub issuer + AWS consumer first, Azure FIC as the depth tranche (its exact-match and flexible-expression semantics are the least-tooled corner), then GCP CEL and non-GitHub issuers. Fully offline: JSON vectors + pytest, no cloud account required.

Why this project exists (for me)

Closes a specific, recurring gap: multi-cloud IAM / OIDC trust-boundary depth (AWS + Azure). Writing a falsifiable, cited test case about a trust rule forces genuinely understanding the rule — active-recall learning with a public artifact as the receipt.

License

Dual-licensed to maximize adoptability:

  • Vector data (vectors/) — CC0-1.0 (public-domain dedication). Embed the vectors in your tool's test suite with zero attribution or licensing friction — that frictionlessness is the point. See vectors/LICENSE.
  • Everything else (the reference matcher, schema, docs) — Apache-2.0. See LICENSE.

Metadata

Release files for subvectors 0.7.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for subvectors 0.7.0
File Size Uploaded
subvectors-0.7.0.tar.gz 196.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for subvectors 0.7.0
File Interpreter ABI Platform
subvectors-0.7.0-py3-none-any.whl Python 3 none any Details

Total release size: 303.9 kB

Release files / subvectors-0.7.0.tar.gz

Download URL subvectors-0.7.0.tar.gz
Size 196.8 kB
Tags Source
SHA-256 checksum
How to use checksums
21ebf4ed4cc6f8deebf94e243618b6e7a25c5fa1233259ba9fde6e82c18d030d
BLAKE2b-256 checksum
How to use checksums
27af294bbd37240a21d8a6ac69228bfffeab8fe07b4898ac9f2db396d4acc949
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release files / subvectors-0.7.0-py3-none-any.whl

Download URL subvectors-0.7.0-py3-none-any.whl
Size 107.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e429c0e6ea38c4104f4bfa7f4f2f3c7a256073ac8e6bf91094122be084aa7653
BLAKE2b-256 checksum
How to use checksums
67049e30ec134f3870b7b3d44f7fedf189de2e81650c4f0265af8c9f98ddc354
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 8, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.7.0 This release

2 release files

0.6.0

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.2

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page