Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: CI

on:
push:
branches: [main, master]
branches: [main, master, "release/**"]
pull_request:
branches: [main, master]
branches: [main, master, "release/**"]

jobs:
test:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

**Scoped authorization for AI-shaped scientific work**

[![Version](https://img.shields.io/badge/version-0.8.1-blue)](https://github.com/fraware/SCOPE/releases)
[![Version](https://img.shields.io/badge/version-1.0.0-blue)](https://github.com/fraware/SCOPE/releases)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
[![CI](https://github.com/fraware/SCOPE/actions/workflows/ci.yml/badge.svg)](https://github.com/fraware/SCOPE/actions/workflows/ci.yml)
Expand Down
47 changes: 29 additions & 18 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,54 @@

| Version | Supported | Notes |
| ------- | --------- | ----- |
| 0.8.x | Yes | Current release line; security fixes backported here |
| 0.7.x | Best effort | Prior institutional pilot line; upgrade to 0.8.x recommended |
| 0.6.x and earlier | No | Unsupported; no security patches |
| 1.0.x | Yes | Current stable line; contract freeze |
| 0.11.x | Yes | Workflow release; security fixes backported when feasible |
| 0.10.x | Best effort | Production trust line; upgrade to 1.0.x recommended |
| 0.9.x | Best effort | Ecosystem demo line |
| 0.8.x | Best effort | Prior release line |
| 0.7.x and earlier | No | Unsupported |

Report issues against the latest **0.8.x** release on [main](https://github.com/fraware/SCOPE).
Report issues against the latest **1.0.x** release on [main](https://github.com/fraware/SCOPE).

## Reporting a vulnerability

Report security issues privately via GitHub Security Advisories on [fraware/SCOPE](https://github.com/fraware/SCOPE/security/advisories/new). Do not open public issues for undisclosed vulnerabilities.

## v0.8 security model
## v1.0 security model

SCOPE v0.8.x builds on schema validation, canonical hashing, hash-chained ledger events, explicit expiration checks, and fail-closed behavior for unknown scopes, invalid roles, and forbidden queue transitions.
SCOPE v1.0 builds on schema validation, canonical hashing, hash-chained ledger events, explicit expiration checks, and fail-closed behavior for unknown scopes, invalid roles, and forbidden queue transitions.

**Cryptography and signing**

- Ed25519 signatures on decisions and grants when production signing is enabled (`SCOPE_PRODUCTION_MODE`, minimum signing assurance policy in `policy/minimum_signing_assurance.yaml`)
- Signing assurance levels (SAL0–SAL4) with registry key binding and reviewer public-key references; external HSM/KMS interface documented for SAL4 (`docs/signing_assurance.md`, `docs/key_management.md`)
- Combined `scope_trust_root_hash` ties policy and reviewer registry integrity into decision, grant, and PCS export provenance
- Ed25519 signatures on decisions and grants when production signing is enabled
- Signing assurance levels (SAL0–SAL4) with KMS reference adapter (`--signing-provider kms`)
- Combined `scope_trust_root_hash` ties policy and reviewer registry integrity into PCS export provenance

**Identity**

- Identity assurance levels (IAL0–IAL4) with provenance on decisions and session grants (`scope/identity_assurance.py`, `docs/identity_assurance.md`)
- Optional OIDC/JWT verification (`SCOPE_OIDC_*`, `scope identity verify-token`) for institutional identity claims; org RBAC in `policy/org_rbac.yaml` is separate from SCOPE scope authority
- Identity assurance levels (IAL0–IAL4); production mode rejects IAL0 unless `SCOPE_ALLOW_DEV_IAL0`
- Pluggable OIDC and SAML providers (`scope/identity_providers.py`)
- SCIM/LDAP RBAC sync via `scope rbac sync`

**Ledger and delivery**

- Local hash-chained JSONL ledger with verification APIs
- Optional remote HTTP append sink (`SCOPE_LEDGER_REMOTE_URL`); delivery semantics `best_effort`, `at_least_once` (spool), and `fail_closed` for high-risk grant issuance when remote delivery is required
- Runtime violation and expiration events for PF feedback loops; remote sink is not a WORM or authoritative tamper-evident store
- Local hash-chained JSONL ledger with WORM and verified remote sink options
- Delivery modes: `best_effort`, `at_least_once`, `fail_closed`
- REST API audit logging to ledger

**AKTA review contract**

- Signed `summary.json` artifacts validated against split schemas for `completed` vs `session_required` (`scope-akta-review-v0.8.1`); consumers must branch on `summary.status`
- Frozen at `scope-akta-review-v1.0`; consumers branch on `summary.status`

**Workflow**

- Tenant-isolated review queues via `X-Scope-Tenant-Id`
- Webhook notifications on SLA breach

**Known limits**

- No live SAML/SCIM directory sync; RBAC and identity mapping are file-based
- Reviewer judgment, domain safety, and physical lab safety are out of scope
- See [docs/threat_model.md](docs/threat_model.md), [docs/trusted_boundary.md](docs/trusted_boundary.md), and [docs/limitations.md](docs/limitations.md) for residual risk and deployment boundaries.
- SAML verification requires external sidecar or pre-verified assertions in reference adapter
- Email notifications require institutional SMTP wiring
- Reviewer judgment and physical lab safety remain out of scope

See [docs/threat_model.md](docs/threat_model.md), [docs/trusted_boundary.md](docs/trusted_boundary.md), [docs/compatibility_matrix.md](docs/compatibility_matrix.md), and [docs/limitations.md](docs/limitations.md).
8 changes: 7 additions & 1 deletion adapters/generic_rest/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,9 +464,15 @@ def list_review_queue(queue_dir: str | None = None) -> dict[str, Any]:


def _find_queue_path(queue_id: str, queue_dir: str | None = None) -> Path:
from scope.errors import ScopeValidationError
from scope.review_queue import ReviewQueue, list_queue_files

for path in list_queue_files(queue_dir):
engine = get_engine()
try:
effective = engine.effective_queue_dir(queue_dir)
except ScopeValidationError as exc:
raise HTTPException(status_code=403, detail=str(exc)) from exc
for path in list_queue_files(effective):
entry = ReviewQueue.load(path)
if entry.queue_id == queue_id:
return path
Expand Down
14 changes: 10 additions & 4 deletions docs/akta_review_contract.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# AKTA Review Output Contract

SCOPE v0.8.1 splits the `scope akta review` output contract by `summary.status`.
SCOPE v1.0 splits the `scope akta review` output contract by `summary.status`.

## Contract version

**Frozen at v1.0:** `scope-akta-review-v1.0` (`scope.integration_versions.AKTA_REVIEW_CONTRACT_VERSION`).

Backward compatible with v0.8.1 and v0.9 consumers when branching on `summary.status`.

## Branching rule

Expand All @@ -13,7 +19,7 @@ Consumers **must** branch on `summary.status`:

The two schemas are mutually exclusive: completed summaries cannot carry session fields (`session_id`, `required_roles`, `message`); session summaries cannot carry grant/decision fields (`decision_path`, `grant_path`, `approved_scope`, IAL/SAL, etc.).

Contract version constant: `scope-akta-review-v0.8.1` (`scope.integration_versions.AKTA_REVIEW_CONTRACT_VERSION`).
Contract version constant: `scope-akta-review-v1.0` (`scope.integration_versions.AKTA_REVIEW_CONTRACT_VERSION`).

## Artifacts

Expand All @@ -36,7 +42,7 @@ Required fields:
"grant_path": "...",
"approved_scope": "...",
"requested_scope": "...",
"adapter_contract_version": "scope-akta-review-v0.8.1",
"adapter_contract_version": "scope-akta-review-v1.0",
"identity_assurance_level": "IAL0",
"signing_assurance_level": "SAL1",
"production_mode": false
Expand All @@ -60,7 +66,7 @@ Required fields:
"session_id": "SCOPE-SESS-...",
"required_roles": ["domain_scientist", "protocol_owner"],
"message": "Multi-role review session created; submit votes before grant issue.",
"adapter_contract_version": "scope-akta-review-v0.8.1",
"adapter_contract_version": "scope-akta-review-v1.0",
"production_mode": false
}
```
Expand Down
45 changes: 45 additions & 0 deletions docs/compatibility_matrix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Compatibility Matrix (v1.0)

Published version alignment for SCOPE and partner integrations at v1.0.0.

## Core versions

| Component | Version constant | Notes |
|-----------|------------------|-------|
| SCOPE package | `0.11.0` → `1.0.0` | Semver from `scope/_version.py` |
| Policy bundle | `scope-core-v1.0` | YAML `version` field |
| AKTA review contract | `scope-akta-review-v1.0` | Branch on `summary.status` |
| PF obligation | `pf-core-v0.5` | `obligation_version` |
| PCS manifest | `pcs-v0.5` | `manifest_version` |
| VSA report import | adapter-local | No semver field; schema-stable fields documented |

## Cross-repo compatibility

| SCOPE | AKTA | PF-Core | PCS | VSA |
|-------|------|---------|-----|-----|
| 1.0.x | ≥ 0.4 trigger aliases | pf-core-v0.5 | pcs-v0.5 | ScientificReport v1 |
| 0.11.x | scope-akta-review-v0.9+ | pf-core-v0.5 | pcs-v0.5 | ScientificReport v1 |
| 0.10.x | scope-akta-review-v0.9+ | pf-core-v0.5 | pcs-v0.5 | ScientificReport v1 |
| 0.9.x | scope-akta-review-v0.9 | pf-core-v0.4–v0.5 | pcs-v0.4–v0.5 | ScientificReport v1 |
| 0.8.x | scope-akta-review-v0.8.1 | pf-core-v0.5 | pcs-v0.5 | ScientificReport v1 |

## Schema stability (v1.0 freeze)

Stable fields in `schemas/` will not be removed or change type without a major SCOPE bump. Deprecated fields remain readable for one major release with documented migration paths.

| Schema | Stable since |
|--------|--------------|
| `scope_akta_review_summary.schema.json` | v1.0.0 |
| `scope_akta_review_session_summary.schema.json` | v1.0.0 |
| `pf_scope_obligation.schema.json` | v0.7.0 |
| `pcs_scope_artifact.schema.json` | v0.7.0 |
| `scope_review_queue.schema.json` | v0.7.0 |

## Migration guides

- **v0.8 → v0.9:** Session-complete AKTA path; contract version bump to `scope-akta-review-v0.9`
- **v0.9 → v0.10:** Production IAL0 rejection; KMS signing provider; RBAC SCIM sync
- **v0.10 → v0.11:** Tenant queue isolation; webhook notifications; REST audit logging
- **v0.11 → v1.0:** Contract freeze at `scope-akta-review-v1.0`; no breaking schema changes

See [akta_review_contract.md](akta_review_contract.md), [external_integration_contracts.md](external_integration_contracts.md).
1 change: 1 addition & 0 deletions docs/production_deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,5 @@ uvicorn adapters.generic_rest.server:app --host 0.0.0.0 --port 8080 --workers 4
```bash
scope quality report --ledger /var/scope/ledger.jsonl --out /tmp/quality.json
python scripts/verify_pilot_fixtures.py
python scripts/verify_ledger_chain.py /var/scope/ledger.jsonl
```
4 changes: 4 additions & 0 deletions evals/run_review_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ def _run_akta_review_scenario(

name = scenario["name"]
session_mode = bool(scenario.get("session_mode"))
session_complete = bool(scenario.get("session_complete"))
with tempfile.TemporaryDirectory() as out_dir:
signing_key: Path | None = None
if scenario.get("sign_before_grant"):
Expand All @@ -251,6 +252,8 @@ def _run_akta_review_scenario(
out_dir=out_dir,
signing_key=signing_key,
session_mode=session_mode,
session_complete=session_complete,
votes=scenario.get("votes"),
)

if session_mode:
Expand Down Expand Up @@ -515,6 +518,7 @@ def _run_scenario_with_engine(
"fail_closed_grant_blocked.json",
"akta_review_signed_summary.json",
"akta_review_session_mode.json",
"akta_review_session_complete.json",
]


Expand Down
45 changes: 45 additions & 0 deletions evals/scenarios/extended/akta_review_session_complete.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "akta_review_session_complete",
"run_akta_review": true,
"session_complete": true,
"akta_record": {
"record_id": "AKTA-EVAL-SESSION-COMPLETE",
"scientific_action_type": "A6_experimental_planning"
},
"akta_trigger": {
"akta_admissibility": "review_required",
"scientific_action_type": "A6_experimental_planning",
"requested_action": "plan_validation",
"requested_tool": "experiment_planner.create_validation_plan",
"requested_scope": "single_validation_plan",
"scientific_context": {
"protocol_version": "protocol_v1",
"evidence_state": "E1_hypothesis"
}
},
"reviewer": {"reviewer_id": "po1", "role": "protocol_owner"},
"decision": {
"type": "approve_narrower_scope",
"approved_scope": "single_validation_plan",
"rationale": "Session-complete orchestration eval"
},
"grant_scope": "single_validation_plan",
"votes": [
{
"reviewer": {"reviewer_id": "ds1", "role": "domain_scientist"},
"decision": {
"type": "approve_narrower_scope",
"approved_scope": "single_validation_plan",
"rationale": "Co-review approves validation plan scope"
}
},
{
"reviewer": {"reviewer_id": "po1", "role": "protocol_owner"},
"decision": {
"type": "approve_narrower_scope",
"approved_scope": "single_validation_plan",
"rationale": "Protocol owner confirms draft scope"
}
}
]
}
9 changes: 5 additions & 4 deletions examples/pilot/README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
# SCOPE Pilot Fixture Pack (v0.8.1)
# SCOPE Pilot Fixture Pack (v1.0.0)

Institutional pilot scenarios generated with SCOPE v0.8.1 CLI and engine APIs. Each subdirectory is self-contained with review artifacts, queue state where applicable, rendered packet markdown, and a quality report snippet.
Institutional pilot scenarios generated with SCOPE v1.0.0 CLI and engine APIs. Each subdirectory is self-contained with review artifacts, queue state where applicable, rendered packet markdown, and a quality report snippet.

| Scenario | Directory | Highlights |
|----------|-----------|------------|
| Single-reviewer protocol draft | [single_reviewer_protocol_draft](single_reviewer_protocol_draft/) | One-shot `scope akta review` |
| Multi-role genomics co-review | [multi_role_genomics_review](multi_role_genomics_review/) | `--session` creates pending session |
| Multi-role genomics co-review | [multi_role_genomics_review](multi_role_genomics_review/) | `--session-complete` issues grant from votes |
| Expired queue reopen | [expired_queue_reopen](expired_queue_reopen/) | Queue `expired` then `reopen` |
| Needs information flow | [needs_information_flow](needs_information_flow/) | `needs_information` to `in_review` |
| Registry-signed decision | [registry_signed_decision](registry_signed_decision/) | `--signing-provider registry --reviewer-id` |

Policy bundle: `scope-core-v0.8`. AKTA review contract: `scope-akta-review-v0.8.1`.
Policy bundle: `scope-core-v1.0`. AKTA review contract: `scope-akta-review-v1.0`.

Each scenario includes `manifest.json` (artifact inventory and schema versions) and `expected_verification.json` (checksums, status values, queue states). Verify offline:

```bash
python scripts/verify_pilot_fixtures.py
python scripts/verify_ledger_chain.py .scope/ledger.jsonl
```
31 changes: 23 additions & 8 deletions examples/pilot/multi_role_genomics_review/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
# Multi-role genomics review

Scenario: weak-evidence experimental planning (A6) requires both `domain_scientist` and `protocol_owner`. `scope akta review --session` creates a review session instead of issuing a grant immediately.
Scenario: weak-evidence experimental planning (A6) requires both `domain_scientist` and `protocol_owner`. Use `--session` for session-required summary or `--session-complete` to orchestrate votes and issue a grant in one command.

## Artifacts

| File | Description |
|------|-------------|
| `scope_review_packet.json` | Review packet |
| `summary.json` | Session-required summary (`status: session_required`) |
| `scope_decision.json` | Aggregated decision (`completed` path) |
| `scope_grant.json` | Issued grant (`completed` path) |
| `summary.json` | Completed AKTA review summary |
| `votes.json` | Reviewer/decision vote manifest for session-complete |
| `reviewer_protocol_owner.json` | Protocol owner reviewer fixture |
| `reviewer_domain_scientist.json` | Domain scientist reviewer fixture |
| `decision_protocol_owner.json` | Vote input for protocol owner |
| `decision_domain_scientist.json` | Vote input for domain scientist |
| `manifest.json` | Artifact inventory and schema versions |
| `expected_verification.json` | Checksums and status expectations |
| `packet_rendered.md` | Markdown packet render |
| `quality_report_snippet.json` | Session-pending quality note |
| `quality_report_snippet.json` | Quality note after grant issue |

## Regenerate session
## Regenerate session-required summary

```bash
scope akta review \
Expand All @@ -29,11 +34,21 @@ scope akta review \
--policy policy
```

## Complete grant (after regeneration)
## Regenerate completed grant (session-complete)

```bash
scope review session vote --session <session_id> ...
scope review session issue-grant ...
scope akta review \
--akta-trigger examples/weak_evidence_validation_review/review_trigger.json \
--akta-record examples/weak_evidence_validation_review/akta_record.json \
--grant-scope single_validation_run_draft \
--reviewer examples/pilot/multi_role_genomics_review/reviewer_protocol_owner.json \
--decision-rationale "Multi-role session-complete grant." \
--out-dir examples/pilot/multi_role_genomics_review \
--session-complete \
--votes examples/pilot/multi_role_genomics_review/votes.json \
--policy policy
```

See `examples/weak_evidence_validation_review/README.md` for the full vote workflow.
REST equivalent: pass `session_complete: true` and `votes[]` to `POST /v0/akta/review` or use `scripts/akta_rest_review.py --session-complete --votes ...`.

See `examples/weak_evidence_validation_review/README.md` for the underlying review scenario.
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
{
"checksums": {
"quality_report_snippet.json": "sha256:c949d9e671baa36c95d6c8bb20fb0f30e571173835dff2bc269a4c9d95da8051",
"scope_review_packet.json": "sha256:654292d3b72dfef1fbd5aa38ed191abdfdab4b3a7244255226fa8e74fb9752ac",
"summary.json": "sha256:9061c4c9d4e517d5ed60ce562fcdbe2bb0fc2d98143ad3d3b9826e090dbda9b3"
"quality_report_snippet.json": "sha256:2a87b022dd1ce8c8c9525310b93ee63db937b47c1ded01f52013cd6cf64f2853",
"scope_decision.json": "sha256:08d9d02b4b93da199f764234895d6a6ea4b240aa433e9641b34b97361969560a",
"scope_grant.json": "sha256:301fff20134c507dc1916a2c2eb60e17f9711439db0a46ef1bdc7edfa28ed5af",
"scope_review_packet.json": "sha256:09629eee028bb8cda2b3789542d1835d3908fc7c264187f0f40c5f74f8e6d20d",
"summary.json": "sha256:2733a7ba7c8c5a08ca5cd88cae9ae04bc9b1e5b5c197ab8bd3f21286d3ba1707"
},
"forbidden_files": [
"scope_grant.json"
],
"forbidden_files": [],
"quality_report_snippet": {
"policy_version": "scope-core-v0.8"
"policy_version": "scope-core-v1.0"
},
"summary": {
"adapter_contract_version": "scope-akta-review-v0.8.1",
"status": "session_required"
"adapter_contract_version": "scope-akta-review-v1.0",
"approved_scope": "single_validation_run_draft",
"status": "completed"
}
}
Loading
Loading