Skip to main content

Governance

The governance model for the Bastion Security Framework, implemented entirely with GitHub-native features.

Principles

  1. All changes via PR — no direct pushes to main, ever
  2. N-of-M approval — critical changes require multiple designated reviewers
  3. Path-scoped ownership — different directories have different review requirements
  4. Auditable rights transfer — adding/removing reviewers is tracked and requires approval
  5. Self-protecting governance — changing the governance rules requires governance approval
  6. Zero third-party dependencies — only GitHub-native features

Roles

Security Board

The primary governance body. Members have authority to approve changes to security-critical content: vectors, semgrep rules, standards, and agents.

  • Size: 5 members (configurable)
  • Quorum: 3 of 5 must approve (configurable per path)
  • GitHub mechanism: @org/security-board team
  • Responsibilities:
    • Review and vote on community vector proposals
    • Approve changes to semgrep rules
    • Approve changes to standards mappings
    • Approve changes to agent definitions
    • Approve governance changes (CODEOWNERS, rulesets)

Agent Maintainers

Responsible for the AI agent definitions and intelligence pipeline.

  • GitHub mechanism: @org/agent-maintainers
  • Scope: agents/, intel/, skills/
  • Note: Changes to agent files also require security board approval (dual ownership)

Tooling Maintainers

Responsible for scripts, MCP server, and build tooling.

  • GitHub mechanism: @org/tooling-team
  • Scope: scripts/, mcp-server/, make/, schema/

Contributors

Anyone can submit a proposal. Contributors don't need org membership — they fork the repo and submit a PR.


GitHub Configuration

Step 1: Create GitHub Teams

In your GitHub organization settings:

Organization → Teams → New team

Team 1: security-board
Description: "Bastion Security Board — approves vectors, rules, and governance changes"
Visibility: Visible
Members: [alice, bob, carol, dave, eve]
Permission: Write access to daml-security-framework repo

Team 2: agent-maintainers
Description: "Bastion Agent Maintainers — maintains AI agent definitions"
Visibility: Visible
Members: [alice, frank]
Permission: Write access to daml-security-framework repo

Team 3: tooling-team
Description: "Bastion Tooling — maintains scripts, MCP server, build system"
Visibility: Visible
Members: [bob, grace]
Permission: Write access to daml-security-framework repo

Step 2: Create CODEOWNERS

Create .github/CODEOWNERS:

# =============================================================================
# Bastion CODEOWNERS — Defines who is automatically requested for review
# Changes to this file require security board approval (self-protecting)
# =============================================================================

# Governance files — security board owns governance
.github/CODEOWNERS @org/security-board
.github/FUNDING.yml @org/security-board
.github/workflows/ @org/security-board

# Security-critical content — security board must review
/vectors/ @org/security-board
/semgrep/ @org/security-board
/standards/ @org/security-board
/intel/ @org/security-board

# Agent definitions — dual ownership (agent maintainers + security board)
/agents/ @org/security-board @org/agent-maintainers

# Skills — dual ownership
/skills/ @org/security-board @org/agent-maintainers

# Tooling — tooling team (security board consulted for security-impacting changes)
/scripts/ @org/tooling-team
/mcp-server/ @org/tooling-team
/make/ @org/tooling-team
/schema/ @org/tooling-team

# Framework config
/registry.yaml @org/security-board
/bastion.yaml.example @org/tooling-team
CLAUDE.md @org/security-board

# Documentation
/docs/ARCHITECTURE.md @org/security-board
/docs/GOVERNANCE.md @org/security-board
README.md @org/security-board

Step 3: Configure Branch Protection on main

Repository Settings → Branches → Add rule for main:

  • Require a pull request before merging
    • Require approvals: 1 (minimum — rulesets handle the N-of-M)
    • Dismiss stale pull request approvals when new commits are pushed
    • Require review from Code Owners
  • Require status checks to pass before merging
    • Required checks: schema-validation, governance-check (added in Step 5)
  • Require linear history
  • Do not allow bypassing the above settings
    • Include administrators
  • Restrict who can push to matching branches
    • Only: @org/security-board

Step 4: Configure Rulesets

Repository Settings → Rules → Rulesets → New branch ruleset:

Ruleset 1: Security Content (vectors, rules, standards)

Name: security-content-review
Enforcement: Active
Target: main branch

Rules:
- Require pull request
- Required approvals: 3
- Dismiss stale reviews: Yes
- Require review from specific team:
Team: @org/security-board
Required approvals: 3
File patterns:
- vectors/**
- semgrep/**
- standards/**
- intel/**
- registry.yaml

- Require status checks:
- schema-validation
- duplicate-check

Bypass list: (empty — no one bypasses)

Ruleset 2: Agent and Skills Changes

Name: agent-review
Enforcement: Active
Target: main branch

Rules:
- Require pull request
- Required approvals: 2
- Require review from specific team:
Team: @org/security-board
Required approvals: 1
File patterns:
- agents/**
- skills/**

- Require review from specific team:
Team: @org/agent-maintainers
Required approvals: 1
File patterns:
- agents/**
- skills/**

Bypass list: (empty)

Ruleset 3: Governance Changes (highest bar)

Name: governance-review
Enforcement: Active
Target: main branch

Rules:
- Require pull request
- Required approvals: 4
- Require review from specific team:
Team: @org/security-board
Required approvals: 4
File patterns:
- .github/CODEOWNERS
- .github/workflows/governance*.yml
- docs/GOVERNANCE.md

Bypass list: (empty — governance changes require near-unanimity)

Ruleset 4: Tooling Changes

Name: tooling-review
Enforcement: Active
Target: main branch

Rules:
- Require pull request
- Required approvals: 1
- Require review from specific team:
Team: @org/tooling-team
Required approvals: 1
File patterns:
- scripts/**
- mcp-server/**
- make/**
- schema/**

Bypass list: (empty)

Step 5: GitHub Actions (Validation Only)

These actions validate PR content — they do NOT enforce approval logic (rulesets handle that).

.github/workflows/validate-proposal.yml

name: Validate Proposal
on:
pull_request:
paths:
- 'vectors/**'
- 'semgrep/**'

jobs:
schema-validation:
name: schema-validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install dependencies
run: pip install pyyaml

- name: Validate vector YAML schema
run: python scripts/validate_schema.py

- name: Check for duplicate vector IDs
run: python scripts/check_duplicates.py

- name: Validate semgrep rules syntax
run: |
pip install semgrep
semgrep --validate --config semgrep/

duplicate-check:
name: duplicate-check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check for duplicate CWEs and vector names
run: python scripts/check_duplicates.py

.github/workflows/label-proposal.yml

name: Label Proposal PR
on:
pull_request:
paths:
- 'vectors/**'

jobs:
label:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v4

- name: Detect domain and severity
id: detect
run: |
# Parse the changed vector files to extract domain and severity
python scripts/detect_proposal_metadata.py >> "$GITHUB_OUTPUT"

- name: Apply labels
uses: actions/github-script@v7
with:
script: |
const domain = '${{ steps.detect.outputs.domain }}';
const severity = '${{ steps.detect.outputs.severity }}';
const labels = ['proposal', `domain:${domain}`, `severity:${severity}`];
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
labels: labels
});

Step 6: PR Templates

.github/PULL_REQUEST_TEMPLATE/vector-proposal.md

## Vector Proposal

### Proposed Vector
- **Name:**
- **Domain:** authorization | arithmetic | temporal | state
- **Severity:** CRITICAL | HIGH | MEDIUM | LOW
- **CWE:**

### Evidence
<!-- How was this discovered? Link to external source, audit finding, or code review. -->

### Applicability
<!-- Does this apply to ANY DAML/Canton project, or only specific implementations? -->

### Mitigation Pattern
```daml
-- DAML code showing the fix

Test Evidence

Checklist

  • Vector applies to generic DAML/Canton patterns (not project-specific)
  • CWE classification verified
  • Mitigation pattern is complete and DAML-idiomatic
  • No project-specific file paths, names, or business logic
  • Checked for duplicates against existing vectors

---

## Rights Transfer Protocol

### Adding a New Board Member

```mermaid
flowchart TD
A[Member opens nomination Issue] --> B[7-day discussion period]
B --> C[Org owner creates membership PR]
C --> D{3 of 5 board members approve?}
D -->|Approved| E[Member added to team]
D -->|Rejected| F[Issue closed with feedback]
E --> G[Logged in org audit log]
  1. A current security board member opens a GitHub Issue nominating a new member
  2. 7-day discussion period for the board to evaluate the candidate
  3. Org owner or team maintainer creates a team membership change
  4. 3 of 5 current board members must approve
  5. On approval, the new member is added to @org/security-board
  6. Change is logged in the GitHub org audit log with timestamp and actor
  7. New member immediately has approval authority on future PRs

Removing a Board Member

  1. A current board member opens a GitHub Issue proposing removal (with reason)
  2. 7-day discussion period
  3. 3 of 5 current board members must approve the removal
  4. Org owner removes the member from @org/security-board
  5. Authority is revoked immediately — pending reviews by this member no longer count

Emergency: Board Member Compromise

This is the only scenario where removal happens before board vote — compromise response must be immediate. The org owner acts unilaterally and notifies the board after the fact.


Approval Requirements Summary

What changedWho reviewsApprovals needed
vectors/community/**@org/security-board3 of 5
semgrep/**@org/security-board3 of 5
standards/**@org/security-board3 of 5
intel/**@org/security-board3 of 5
agents/**@org/security-board + @org/agent-maintainers1 from each
skills/**@org/security-board + @org/agent-maintainers1 from each
scripts/**, mcp-server/**@org/tooling-team1
.github/CODEOWNERS@org/security-board4 of 5
docs/GOVERNANCE.md@org/security-board4 of 5
registry.yaml@org/security-board3 of 5
README.md, docs/*@org/security-board1

Audit Trail

All governance events are tracked in GitHub's native audit log:

EventWhere loggedRetention
PR createdRepository activityForever (git history)
PR approved/rejectedPR review historyForever
PR mergedGit log + PR historyForever
Team member addedOrg audit log180 days (free/Team)
Team member removedOrg audit log180 days (free/Team)
Ruleset changedOrg audit log180 days
Branch protection changedOrg audit log180 days

For longer retention of team membership changes, consider exporting the audit log periodically via the GitHub API (GET /orgs/{org}/audit-log).