Skip to content
Closed
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
13 changes: 13 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,19 @@ sequenceDiagram
- Rust remains the psychometric arithmetic owner. Repair never substitutes
Python for scoring math.

## Object-storage governance (2026-08-16)

Central `.github` publishes a provider-neutral `object_storage` contract.
Naruon and other products keep their own adapters. The executable check is
`scripts/ci/validate_object_storage_contract.py`. HTTPS, exact-host
allowlists, tenant-purpose binding, server-side encryption, SHA-256-or-stronger
integrity, distinct lifecycle states, and non-destructive rollback are
required. Denied private-network trust also rejects special-use internal
suffixes. CSAP and SOC 2 remain design constraints, not certification claims.
Operational PII is not blanket-masked. Product adapters prove write/read/delete
timeout and partial-upload behavior with
`docs/object-storage/PRODUCT_ACCEPTANCE_TEMPLATE.md`.

## Quality gates

`scripts/ci/` ships with 100% statement/branch coverage and 100% docstrings.
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Semantic Versioning where the repository publishes a release.

### Added

- Added a provider-neutral object-storage contract with an executable fail-closed validator, JSON Schema, naruon-shaped example, and APA 7 doctoring so AWS S3 and S3-compatible endpoints share one HTTPS, exact-host, integrity, retention, and rollback policy (ContextualWisdomLab/.github#1019, ContextualWisdomLab/naruon#1364).
- Added a trusted pull-request comment router for `@cwl-noema-review` and review-only `@opencode-agent` dispatches, with an organization sweep, exact-head receipts, repository allowlisting, fixed runners, immutable checkout pins, and a permanent 100% statement/branch/docstring quality gate.
- Added exact-base `uv.lock` materialization that reconstructs standalone nested projects with a checksum-pinned official `uv` exporter, isolated frozen/offline execution, strict exact-pin and SHA-256 output validation, and complete Python 3.10/3.14 quality evidence.
- Added a permanent exact-head contract workflow for the hourly review-repair scheduler, immutable reusable-workflow source, NVIDIA NIM model boundary, credential isolation, and fail-closed unattended-agent permissions.
Expand All @@ -26,6 +27,11 @@ Semantic Versioning where the repository publishes a release.

### Fixed

- Closed the object-storage contract around exact lowercase DNS hosts, TCP port range, finite RFC 8259 numbers, nested JSON Schema objects, and typed observability labels so hardening tests cannot pass a metadata, Unicode, or unhashable-label document.
- Removed the leftover one-shot object-storage repair workflow so Scorecard Token-Permissions no longer sees workflow-default `contents: write` after the hardening is already committed.
- Rejected decimal, hexadecimal, and dotted-numeric IPv4 aliases in object-storage host allowlists so Strix-proven metadata-service SSRF bypasses fail closed.
- Rejected multicast `.local`, metadata, and cluster-local names from object-storage allowlists, and rejected RFC 6761/6762 internal suffixes when private-network trust is denied, so a `denied` policy cannot admit `minio.internal`.
- Required tenant- and purpose-bound provider selection, aligned the portable JSON Schema with the executable value constraints, and added the product write/read/delete acceptance template so sibling adapters can prove compatibility without copying central code.
- Materialized base Python locks only when every package line is an exact SHA-256 pin or a bounded relative `-r`/`--requirement` include. A lone `--require-hashes` directive, a dotted include such as `./lock.txt`, or `-r other-hashes.txt` no longer enters the trusted build context.
- Refused a conflict-scope repository root whose immediate parent is a symbolic link, so a swapped parent cannot redirect the canonical worktree after the last-component check (CWE-367).
- Bounded the Strix quality self-test's deterministic timeout fixtures to 3-second process and 5-second fake-sleep budgets so exact-head policy evidence completes inside the existing job limit without changing production Strix scanner timeouts, providers, credentials, or review semantics.
Expand Down
103 changes: 103 additions & 0 deletions docs/doctoring/object-storage-contract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Object-storage contract: evidence and design record

검토 기준일: **2026-08-16**

## Incident / buyer-visible gap

Sibling products persist customer or evidence objects in AWS S3 or
S3-compatible stores. Without a central executable contract, each repository
can invent endpoint, credential, encryption, integrity, retention, and
rollback rules. That drift is a procurement and data-loss risk for buyers who
must keep documents, even when Naruon already implements a scoped adapter in
ContextualWisdomLab/naruon#1364.

This record does not implement Naruon storage. It records the organization
policy and the fail-closed check that leaf repositories can cite.

## Decision

1. Treat AWS S3 and S3-compatible HTTPS stores as one `object_storage`
capability.
2. Require HTTPS, exact-host allowlists, no wildcards, and no automatic
redirects (CWE-918).
3. Require explicit private-network trust. Implicit RFC1918, metadata-service,
multicast `.local` (Cheshire & Krochmal, 2013b), or special-use internal
suffixes (Cheshire & Krochmal, 2013a) are not authorized unless the exact
host is named after an explicit trust decision. Multicast `.local` names
are never unicast endpoints.
4. Require least-privilege object permissions and prohibit public ACLs, public
buckets, and browser-exposed long-lived credentials (CWE-798; CWE-200).
5. Require server-side encryption and fail-closed content-length plus SHA-256
or stronger read verification (Amazon Web Services, 2024a, 2024b).
6. Keep lifecycle states distinct. `consumed` does not imply immediate
deletion unless the product explicitly configures zero retention. Legal hold
and archive remain separate from transient reprocessing retention.
7. Refuse rollback that deletes customer data after a partial
migration or backfill.
8. Forbid bucket names, object keys, credentials, and raw PII as unbounded
telemetry labels. This is not a blanket operational PII mask.
9. Record CSAP and SOC 2 only as design constraints. The contract must not
claim certification.
10. Require tenant- and purpose-bound provider selection so one credential or
bucket cannot serve unrelated tenants or jobs.
11. Ship an executable validator and a product acceptance template. Prose
alone does not close ContextualWisdomLab/.github#1019.

## Trust boundary

- Central `.github` owns the schema, policy, doctoring record, and validator.
- Product repositories own adapters, buckets, keys, credentials, and evidence
objects.
- NVIDIA NIM / OpenCode credentials are untouched.
- The validator never prints bucket names, object keys, or secrets from a
failing document beyond the field that violated the closed policy.

## Verification contract

`tests/test_object_storage_contract.py` proves the checked-in example passes,
the schema keys match production constants, and each fail-closed control has a
unique rejection. `tests/test_object_storage_contract_hardening.py` proves
nested schema objects stay closed, NaN/Infinity are rejected, exact-host
allowlists exclude localhost, metadata, cluster-local names, IPv4 and IPv6
literals, decimal or hexadecimal IP aliases, Unicode, case aliases, and
multicast `.local` names, a denied private-network policy rejects
single-label and special-use internal hosts, custom endpoints reject ports
above 65535, schema value constraints match the validator, tenant-purpose
binding is mandatory, and malformed observability labels raise policy
errors instead of TypeError. Local quality remains 100% statement/branch
coverage and 100% docstrings.

## Rollback

Revert the validator, schema, example, policy, and this record together. Do
not keep a schema that the executable check no longer enforces.

## References (APA 7th)

Cheshire, S., & Krochmal, M. (2013a). *Special-use domain names* (RFC 6761).
Internet Engineering Task Force. https://www.rfc-editor.org/rfc/rfc6761

Cheshire, S., & Krochmal, M. (2013b). *Multicast DNS* (RFC 6762). Internet
Engineering Task Force. https://www.rfc-editor.org/rfc/rfc6762

Amazon Web Services. (2024a). *Checking object integrity for data uploads in
Amazon S3*. Amazon Simple Storage Service User Guide.
https://docs.aws.amazon.com/AmazonS3/latest/userguide/checking-object-integrity-upload.html

Amazon Web Services. (2024b). *Using server-side encryption with AWS KMS keys
(SSE-KMS)*. Amazon Simple Storage Service User Guide.
https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingKMSEncryption.html

Amazon Web Services. (n.d.). *Authenticating requests (AWS Signature Version
4)*. Amazon Simple Storage Service API Reference.
https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html

MITRE. (n.d.-a). *CWE-200: Exposure of sensitive information to an
unauthorized actor*. CWE List.
https://cwe.mitre.org/data/definitions/200.html

MITRE. (n.d.-b). *CWE-798: Use of hard-coded credentials*. CWE List.
https://cwe.mitre.org/data/definitions/798.html

MITRE. (n.d.-c). *CWE-918: Server-side request forgery (SSRF)*. CWE List.
https://cwe.mitre.org/data/definitions/918.html
78 changes: 78 additions & 0 deletions docs/object-storage/CWL_OBJECT_STORAGE_CONTRACT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# CWL object-storage contract

This repository owns the reusable `object_storage` policy and the executable
check `scripts/ci/validate_object_storage_contract.py`. Product repositories
keep their own adapters, databases, and evidence objects. Naruon
[ContextualWisdomLab/naruon#1364](https://github.com/ContextualWisdomLab/naruon/pull/1364)
is the current concrete consumer and remains the owner of its document-storage
implementation.

AWS-managed S3 and S3-compatible HTTPS endpoints are one provider-neutral
capability. They are not an AWS-only product assumption.

## Closed controls

A contract JSON document is valid only when every control below is true.

| Control | Required value |
|---|---|
| Transport | `https` only |
| Hosts | exact-host allowlist; no wildcards; no automatic redirects; no multicast `.local` or metadata names |
| Private networks | `explicit_allowlist` or `denied`; never implicit RFC1918, RFC 6761/6762, or `.internal` access |
| Credentials | scoped secret registry or workload identity; never broadcast, browser-exposed, or ambient process-wide |
| Permissions | least privilege; public ACLs and public buckets prohibited |
| Encryption | server-side encryption `required` |
| Integrity | content length plus SHA-256 or stronger; fail-closed read verification |
| Lifecycle | `pending`, `available`, `consumed`, `archived`, and `held` are distinct; `consumed` does not delete unless zero retention is explicit |
| Rollback | a partial migration must not delete customer data |
| Names | persisted metadata uses multiword `snake_case` |
| Tenant binding | provider selection is tenant- and purpose-bound |
| Telemetry | bucket names, object keys, credentials, and raw PII are forbidden high-cardinality labels |
| Assurance | CSAP and SOC 2 are design constraints, not certifications |

Operational PII stays usable through the owning product. Forbidding
high-cardinality labels is not a blanket PII mask.

## Endpoint classes

1. **AWS-managed S3 HTTPS endpoints** — `provider_class` is `aws_s3` and every
host is an exact Amazon S3 regional or dual-stack name.
2. **Public S3-compatible HTTPS endpoints** — `provider_class` is
`s3_compatible` and every host is an exact public DNS name.
3. **Authorized private-network endpoints** — `private_network_trust` is
`explicit_allowlist` and each private host is named. Implicit RFC1918,
link-local, metadata-service, multicast `.local`, or special-use
`.internal` / `.corp` / `.lan` access is rejected unless that exact host
is named after an explicit trust decision. Multicast `.local` names are
never valid unicast endpoints.

Workload-identity and instance-metadata access require their own SSRF review.
This contract does not grant that access.

## Product next actions

On success the consumer persists or reads the object under its own schema and
records a purpose-bound audit event without bucket, key, credential, or raw PII
labels. On rejection, timeout, duplicate, or partial upload the consumer leaves
the previous durable object in place. Rollback never deletes customer data
because a backfill step only partly succeeded. Product repositories then run
the write/read/delete failure-injection lane in
`docs/object-storage/PRODUCT_ACCEPTANCE_TEMPLATE.md`.

## Verification

```bash
python3 scripts/ci/validate_object_storage_contract.py \
--path schemas/examples/cwl-object-storage-v1.example.json
```

The checked-in example is the naruon-shaped fixture. A product repository may
commit its own contract file and run the same command in its quality job. The
issue is not closed by prose alone: the executable check is the acceptance
evidence.

## Schema

`schemas/cwl-object-storage-v1.schema.json` lists the closed top-level keys.
The Python validator is authoritative when a JSON Schema library is not
installed.
46 changes: 46 additions & 0 deletions docs/object-storage/PRODUCT_ACCEPTANCE_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Object-storage product acceptance template

Use this checklist in the product repository that owns the adapter. Central
`.github` does not store customer objects. The current consumer is
[ContextualWisdomLab/naruon#1364](https://github.com/ContextualWisdomLab/naruon/pull/1364).

## Before you claim S3 compatibility

1. Commit a contract JSON that passes
`python3 scripts/ci/validate_object_storage_contract.py --path <your-contract.json>`.
2. Keep provider selection tenant- and purpose-bound. Do not share one
credential or bucket across tenants or unrelated jobs.
3. Persist provider and object metadata in 3NF with multiword `snake_case`
names. Do not store credentials in events, logs, SBOMs, or model context.

## Failure-injection lane

A product may call itself S3-compatible only after a real object-store lane
(LocalStack or the purchased endpoint) proves write/read/delete behavior
against the current head, including:

| Case | Required next action |
|---|---|
| write timeout | Leave the previous durable object in place and record a purpose-bound audit event |
| read timeout | Fail closed; do not treat a truncated body as valid evidence |
| delete timeout | Retry the same deterministic key; do not enumerate the bucket |
| partial or aborted upload | Do not publish a `available` object; compensate without deleting older customer data |
| digest or content-length mismatch | Reject the read; keep the prior object |

## Rollback and retention

A partial migration or backfill must not delete customer data. `consumed`
does not delete unless the product explicitly configures zero retention.
Legal hold and archive stay distinct from the reprocessing window.

## Telemetry

Emit OpenTelemetry or audit evidence without `bucket`, `object_key`,
`credential`, or `raw_pii` labels. Operational PII that the product must
process stays in the product data plane; do not blanket-mask it.

## Close the issue only with current-head proof

Point the product PR at this template, the central contract SHA, and the
exact-head integration run. Prose without that run does not close
ContextualWisdomLab/.github#1019.
Loading
Loading