# Contributing a community test suite

This guide covers the full submission flow for adding a new entry to
`src/agentsec/suite_registry/community-suites.yaml`.

## Bundle structure

```
your-suite/
  manifest.yaml         # required
  cases/                # required, at least one *.yaml of TestCase entries
    01_xxx.yaml
  fixtures/             # optional, referenced by `fixture.path` in case YAMLs
  README.md             # optional; first paragraph shown by `agentsec suite info`
```

A copy-paste starting point is at
[`examples/sample-community-suite/`](../../examples/sample-community-suite/).

## Manifest schema

```yaml
schema_version: 1
name: my-suite                     # [a-z0-9][a-z0-9-]{0,62}; equals registry key
version: 1.0.0                     # SemVer 2.0
description: One-line summary
authors:
  - name: jdoe
    url: https://github.com/jdoe   # optional
license: MIT                       # SPDX identifier from the AgentSec subset
agentsec_min_version: 0.9.0
threat_refs_required:
  - TI-OPENCLAW-CVE-2026-25253     # every TI ID referenced by your cases
  - TI-OWASP-AGENTIC-2026-A1
case_count: 13                     # display only; mismatch is a warning
homepage: https://github.com/jdoe/my-suite       # optional
tags: [prompt_injection]                          # optional
```

`SuiteManifest` rejects unknown fields (`extra="forbid"`).

The license must be in the AgentSec SPDX subset shipped at
`src/agentsec/suite_registry/spdx_licenses.txt`. PRs adding common OSS
identifiers are welcome.

## Submission flow

1. Build your bundle in a public GitHub repository at any path.
2. Tag a release (`git tag v1.0.0 && git push --tags`) so the registry
   pin is immutable. The CI hash-drift workflow watches all listed refs
   weekly — using a branch name will eventually open a drift issue.
3. Compute the canonical hash:

   ```bash
   agentsec suite hash ./path/to/your-suite
   ```

4. **If your cases reference TI IDs not yet in the main repo**, open a
   PR adding those rows to
   [`src/agentsec/audit/ioc/threat_intel.yaml`](../../src/agentsec/audit/ioc/threat_intel.yaml).
   This must merge **before or alongside** your registry entry — install
   will fail otherwise.
5. Open a PR adding an entry to
   [`src/agentsec/suite_registry/community-suites.yaml`](../../src/agentsec/suite_registry/community-suites.yaml):

   ```yaml
   suites:
     my-suite:
       source: github
       repo: jdoe/my-repo
       ref: v1.0.0
       subdir: path/to/your-suite
       sha256: <output of `agentsec suite hash`>
       summary: One-line summary
   ```

6. The maintainer will fetch your bundle, recompute the hash, run
   `agentsec suite install` against the entry, and review your test
   cases for content. Expect a couple of round-trips on the cases
   themselves.

## TI ID rule (strict)

`threat_refs_required` must be a subset of the IDs already in
`src/agentsec/audit/ioc/threat_intel.yaml` at install time. There is no
"sidecar TI" mechanism — community suites cannot mutate the local TI
view, since `threat_intel.yaml` drives scoring (`version_patch` finding
severity, KEV escalation). If your case targets a CVE not yet tracked,
add a row to `threat_intel.yaml` first.

## Updating an existing suite

Tag a new release (e.g. `v1.1.0`) and submit a PR updating only `ref`
and `sha256` on the existing entry. Keep `name` stable.

## Why these constraints?

The trust model is:

- The main-repo PR review process is the audit step.
- The registry's `sha256` is what was audited.
- The installer rejects anything that doesn't hash to that exact value.

Signing (sigstore, minisign) is intentionally out of scope — the
PR-plus-pinned-hash model already provides end-to-end traceability for
a single-maintainer project. We can add it if/when the registry
outgrows the main repo.
