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
31 changes: 25 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
# Changelog

All notable changes to Anchor are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
All notable changes to the Anchor governance engine are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

---

## [4.3.5] — 2026-03-23

### Changed
- License corrected to **Apache 2.0** across `README.md`, `setup.py`, and PyPI metadata.
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CHANGELOG entry claims the license was corrected to Apache 2.0 across README/setup.py/PyPI metadata, but setup.py still declares the MIT license classifier and the repo LICENSE file is MIT. Please correct this changelog item or make the corresponding license/metadata changes so the release notes are accurate.

Suggested change
- License corrected to **Apache 2.0** across `README.md`, `setup.py`, and PyPI metadata.
- License metadata clarified and aligned across `README.md`, `setup.py`, and PyPI; project remains **MIT-licensed**.

Copilot uses AI. Check for mistakes.
- PyPI package renamed to `anchor-audit` — `pip install anchor-audit`.
- Updated coverage stats: **43 domain rules**, **170 regulatory mappings**, **9 frameworks/regulators**.

---

## [4.1.2] — 2026-03-22

### Fixed
- **Multi-ID deduplication** — `ANC-NNN` and `FINOS-NNN` aliases no longer both fire for the same violation. Deduplicated on canonical ID + file + line at reporting time.
- **Alias pattern mapping** — mitigation patterns were being mapped to alias IDs instead of canonical IDs, leaving aliases without detection patterns and reporting them as inactive. Patterns now bind to the canonical rule first; aliases receive fully-populated copies.

### Performance
- **Lazy grammar loading** — tree-sitter grammars now load per-language on first use rather than at package import. Eliminates ~3.5s startup overhead on cold installs with multiple language adapters installed.

---

Expand All @@ -25,12 +45,11 @@ All notable changes to Anchor are documented here. Format follows [Keep a Change
### New: Commands
- `anchor sync --restore` — fetches authoritative governance files from registry and restores any tampered or modified files. Logs restores to `.anchor/logs/sync.log` with chain hash.
- `anchor init --all` — installs all available domains, frameworks, and regulators in one command.
- `anchor init --no-sign` — skips remote GOVERNANCE.lock fetch for offline initialisation. Scans run in UNVERIFIED mode until `anchor sync --restore` is run. UNVERIFIED reports are not valid for regulatory submission.
- `anchor init --no-sign` — skips remote GOVERNANCE.lock fetch for offline initialisation. Scans run in UNVERIFIED mode until `anchor sync --restore` is run.

### New: Alias Resolution Chain
- Legacy V3 `ANC-NNN` IDs resolve through FINOS framework layer: `ANC-NNN → FINOS-NNN`.
- FINOS_Framework.anchor is the Rosetta Stone — full mapping in `constitution.anchor` under `legacy_aliases`.
- Aliases inherit severity floor from canonical rule but do not inherit domain ID directly.

### New: Regulator Domains
- `government/RBI_Regulations.anchor` — RBI FREE-AI Report August 2025
Expand All @@ -47,18 +66,18 @@ All notable changes to Anchor are documented here. Format follows [Keep a Change

### Fixed
- `loader.py` — empty `policy.anchor` returned `NoneType` instead of `{}`, causing silent fallback to unpopulated V3 cache. Fixed with `raw = yaml.safe_load(...) or {}`.
- `cli.py` — mitigation patterns were mapping to alias IDs instead of canonical IDs, leaving aliases without detection patterns and reporting them as inactive. Patterns now mapped to canonical rules first; aliases inherit fully-populated copies.
- `cli.py` — mitigation patterns were mapping to alias IDs instead of canonical IDs. Patterns now mapped to canonical rules first; aliases inherit fully-populated copies.
- Duplicate findings — `ANC-NNN` and `FINOS-NNN` no longer both fire for the same finding. Deduplicated on canonical ID + file + line.

### Changed
- `policy.anchor` — `enforce_raise_only: true` is now enforced at the engine level, not just documented. Attempts to lower severity below the constitutional floor are rejected with an error.
- `policy.anchor` — `enforce_raise_only: true` is now enforced at the engine level. Attempts to lower severity below the constitutional floor are rejected with an error.
- `sealed:` and `seal: "sha256:PENDING"` fields removed from `constitution.anchor` — superseded by `GOVERNANCE.lock`.
- `.anchor/` is now committed to the project repository. `.anchor/cache/` is added to `.gitignore` instead.

### Removed
- Monolithic `risk_catalog.yaml` — fully superseded by federated domain architecture.
- Local `.anchor.sig` signature file — superseded by remote `GOVERNANCE.lock`.
- `active_domains` section in `constitution.anchor` — all domains are now mandatory, section is redundant.
- `active_domains` section in `constitution.anchor` — all domains are now mandatory.

---

Expand Down
82 changes: 44 additions & 38 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Contributing to Anchor

Thank you for your interest in contributing to Anchor! This guide will help you get started.
Thank you for your interest in contributing to Anchor. This guide covers everything you need to get started.

🌐 **[anchorgovernance.tech](https://anchorgovernance.tech)** · ✉️ [tan@anchorgovernance.tech](mailto:tan@anchorgovernance.tech)

---

Expand All @@ -17,8 +19,10 @@ cd Anchor

```bash
python -m venv anchor_dev

# Windows
anchor_dev\Scripts\activate

# macOS/Linux
source anchor_dev/bin/activate

Expand All @@ -36,24 +40,22 @@ anchor check --dir . --verbose

## Project Architecture

Understanding the codebase before contributing:

```
anchor/
├── cli.py # CLI entry point (Click framework)
├── cli.py # CLI entry point (Click)
├── core/
│ ├── engine.py # PolicyEngine — tree-sitter AST scanning
│ ├── constitution.py # SHA-256 integrity verification
│ ├── config.py # Pydantic settings (.env loading)
│ ├── policy_loader.py # Federated policy merger
│ └── mapper.py # Threat Model -> Rule mapper
│ ├── loader.py # Federated policy merger
│ └── mapper.py # Threat Model Rule mapper
├── adapters/ # Language-specific tree-sitter adapters
└── plugins/ # Extensible plugin system
```

### Key Concepts

- **Constitution** (`constitution.anchor`): Defines WHAT risks exist. Do NOT edit directly — changes go through a PR with hash updates.
- **Constitution** (`constitution.anchor`): Defines WHAT risks exist. SHA-256 sealed via remote `GOVERNANCE.lock`. Do NOT edit directly — changes go through a PR with hash updates.
- **Mitigation Catalog** (`mitigation.anchor`): Defines HOW to detect risks. This is where most pattern contributions go.
- **Policy** (`policy.anchor`): Local project overrides. Not part of the universal package.

Expand All @@ -63,7 +65,7 @@ anchor/

### 1. Adding Detection Patterns (Most Common)

The easiest and most impactful contribution. Add a new regex or AST pattern to `mitigation.anchor`:
Add a new regex or AST pattern to `mitigation.anchor`:

Comment on lines 41 to 69
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CONTRIBUTING.md refers to core/loader.py as the federated policy merger and instructs contributors to edit mitigation.anchor/constitution.anchor without specifying the correct location. In the repo, governance sources are under anchor/governance/ (and .anchor/ is generated by anchor init), and anchor/core/policy_loader.py still exists/gets imported by the CLI. Please update the architecture + contribution guidance to point to the actual files contributors should modify.

Copilot uses AI. Check for mistakes.
```yaml
# Example: New pattern for ANC-009 (Prompt Injection)
Expand All @@ -79,18 +81,18 @@ The easiest and most impactful contribution. Add a new regex or AST pattern to `

**Pattern Guidelines:**

| Rule | Why |
| -------------------------- | ------------------------------------------------------------ |
| Use context-aware patterns | Don't match every f-string — scope to prompt/LLM vars |
| Prefer regex over AST | Regex is faster and more portable across languages |
| Include `severity` | One of: `info`, `warning`, `error`, `blocker` |
| Test on real code | Run `anchor check --dir ./tests --verbose` before submitting |
| Rule | Why |
|---|---|
| Use context-aware patterns | Don't match every f-string — scope to prompt/LLM variables |
| Prefer regex over AST | Regex is faster and more portable across languages |
| Include `severity` | One of: `info`, `warning`, `error`, `blocker` |
| Test on real code | Run `anchor check --dir ./tests --verbose` before submitting |

### 2. Improving Existing Patterns

If a pattern produces false positives:

1. Open an issue describing the false positive.
1. Open an issue describing the false positive with a minimal reproduction.
2. Propose a refined pattern in a PR.
3. Include a test fixture in `tests/fixtures/` showing the fix.

Expand All @@ -102,40 +104,45 @@ Anchor uses `tree-sitter` for AST parsing. To add a new language:
2. Create an adapter in `anchor/adapters/`
3. Register the file extension mapping in `anchor/core/registry.py`

**Standardization Requirement**: You MUST use these capture names in your queries:
**Capture name standardization** (required):

| Capture | Use For |
|---|---|
| `@func_name` | Function calls |
| `@import_name` | Import statements |
| `@parent_name` | Inheritance / embedding |

### 4. Case Studies

- `@func_name` for function calls
- `@import_name` for imports
- `@parent_name` for inheritance/embedding
Document real-world audits in `case-studies/governance_audits/<project>/`. Include:

### 4. Bug Fixes & Feature Development
- `governance_violations.txt` — raw violation output
- `governance_audit.md` — formatted audit report

### 5. Bug Fixes & Feature Development

1. Check [open issues](https://github.com/Tanishq1030/Anchor/issues) for existing reports.
2. Create a feature branch: `git checkout -b feature/your-feature`
3. Make your changes and test.
3. Make your changes and test thoroughly.
4. Submit a PR with a clear description.

---

## Testing

### Run the Test Suite

```bash
# Run all tests
python -m pytest tests/ -v

# Run compliance test (validates 23-risk detection)
# Run compliance test (validates 43-rule detection)
python tests/compliance_test.py

# Run a quick scan on the project itself
# Quick self-audit
anchor check --dir . --verbose
```

### Adding Test Fixtures

Place test files in `tests/fixtures/`:

```
tests/
├── fixtures/
Expand All @@ -161,36 +168,34 @@ These files are **SHA-256 sealed**. If your PR modifies them:
3. Update the hash in `anchor/core/constitution.py`.
4. Clearly document why the change is needed in the PR description.

> **Note**: Hash changes will be reviewed with extra scrutiny to prevent weakening of security rules.
> **Note**: Hash changes are reviewed with extra scrutiny to prevent weakening of security rules.

### Using Suppression Comments

If your code legitimately triggers a rule (e.g., a security tool using `subprocess`), you can suppress it:

```python
# Governance tool legitimately using subprocess
result = subprocess.run(cmd, capture_output=True) # anchor: ignore ANC-018
```

**Suppression guidelines:**

| Rule | Why |
| ------------------------------- | ----------------------------------------------------------- |
| Use per-rule suppression | `# anchor: ignore ANC-XXX`, not `# anchor: ignore-all` |
| Add a justification comment | Explain **why** the suppression is needed on the line above |
| Never suppress in test fixtures | Test files should trigger rules intentionally |
| Suppressions are git-blamed | Your name is permanently attached to the suppression |
| Rule | Why |
|---|---|
| Use per-rule suppression | `# anchor: ignore ANC-XXX`, not `# anchor: ignore-all` |
| Add a justification comment | Explain **why** the suppression is needed on the line above |
| Never suppress in test fixtures | Test files should trigger rules intentionally |
| Suppressions are git-blamed | Your name is permanently attached to the suppression |

---

## PR Checklist

Before submitting your pull request:

- [ ] Code follows the existing project style
- [ ] New patterns are context-aware (no overly broad matching)
- [ ] Tests pass: `python -m pytest tests/ -v`
- [ ] SHA-256 hashes updated if governance files were modified
- [ ] Suppressions use `# anchor: ignore ANC-XXX` (not `ignore-all`)
- [ ] CHANGELOG.md entry added
- [ ] PR description explains the change and its rationale

---
Expand All @@ -205,6 +210,7 @@ Be respectful and constructive. We are building tools that govern AI safety —

- Open a [Discussion](https://github.com/Tanishq1030/Anchor/discussions)
- File an [Issue](https://github.com/Tanishq1030/Anchor/issues)
- Email: [tan@anchorgovernance.tech](mailto:tan@anchorgovernance.tech)

---

Expand Down
Loading
Loading