stemedb/docs/rfcs/rfc-001-enterprise-policy-aliases.md
jordan 41c676a78e feat: Aphoria enterprise features + ontology SDK + file length compliance
Enterprise Features:
- Hosted mode with remote sync for team pattern aggregation
- Community sharing with privacy-preserving anonymization
- LLM-based semantic claim extraction with Gemini integration
- Pattern learning with promotion to declarative extractors
- High-entropy secrets extractor with configurable thresholds
- Auth bypass and insecure cookies extractors

Module Refactoring:
- Split oversized files to comply with 500-line limit
- Config split: types/core.rs, types/extractors.rs, types/hosted.rs, etc.
- Handlers split: scan.rs, policy.rs, report.rs modules
- Extractors split: declarative/, high_entropy_secrets/, insecure_cookies/
- Learning split: store modules with metrics and persistence

SDK & Ontology:
- stemedb-ontology SDK with fluent builders and StemeDB client
- Pharma domain extractors for FDA Orange Book data
- Consumer health UAT test infrastructure

Code Quality:
- Fixed clippy warnings (needless_borrows_for_generic_args)
- Added KVStore trait imports where needed
- Fixed utoipa path re-exports for OpenAPI docs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 12:55:29 -07:00

931 lines
30 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# RFC-001: Enterprise Policy Alias System
**Date:** 2026-02-05
**Status:** Proposed
**Author:** Aphoria Team
**Target Audience:** Enterprise security teams, CTOs, and development organizations
---
## Executive Summary
Enterprise security teams need to enforce organization-wide security policies across diverse development teams using different programming languages and project structures. The current tail-path matching system works well for bundled RFC/OWASP corpus but fails when security teams create custom policies using logical hierarchies (e.g., `code://standards/tls/*`) that don't align with extractor output (e.g., `code://rust/myapp/tls/*`). This RFC proposes **Policy Aliases**—an explicit mapping layer in Trust Packs that bridges the gap between enterprise policy hierarchies and code extractor conventions, enabling seamless cross-language policy enforcement with full audit trails and cryptographic verification.
---
## Problem Statement
### Current State: Tail-Path Matching Works for Bundled Corpus
Aphoria uses a tail-path matching algorithm that extracts the last two segments of a subject path to create index keys. This enables cross-scheme concept matching:
```
RFC source: "rfc://5246/tls/cert_verification"
Code extractor: "code://rust/myapp/tls/cert_verification"
Both produce key: "tls/cert_verification::enabled"
```
This works because **extractors are intentionally designed** to align with RFC/OWASP hierarchies. The bundled authoritative corpus and code extractors share a common conceptual vocabulary.
### The Enterprise Gap: Policy Hierarchies Don't Match Extractor Output
When enterprise security teams create their own policies, they naturally organize them using **logical domains**, not language-qualified paths:
```toml
# Security team's mental model
subject = "code://standards/tls/cert_verification" # Standards
subject = "code://internal/exceptions/md5_allowed" # Exceptions
subject = "code://vendor/aws/s3/public_access" # Cloud rules
```
But code extractors produce **language-qualified paths**:
```rust
// Rust extractor output
concept_path: "code://rust/myapp/tls/cert_verification"
// Go extractor output
concept_path: "code://go/myapp/tls/cert_verification"
```
**Tail-path matching fails:**
| Source | Path | Extracted Key |
|--------|------|---------------|
| Policy | `code://standards/tls/cert_verification` | `tls/cert_verification::enabled` |
| Code | `code://rust/myapp/tls/cert_verification` | `myapp/tls::enabled` |
The keys don't match because they extract different segments: `standards/tls` vs `rust/myapp/tls`.
### Business Impact
This mismatch has serious consequences for enterprises:
1. **Policy Enforcement Broken:** Security standards don't match code violations
2. **Compliance Risk:** Audits fail when policies exist but aren't enforced
3. **Adoption Blocker:** Enterprises can't use Trust Packs for cross-team governance
4. **False Security:** Teams think they're protected when policies aren't actually matching
**Real-world scenario:** A security team exports a signed Trust Pack with TLS requirements. Development teams import it and run scans. Zero conflicts are reported—not because the code is compliant, but because the matching algorithm never connects policy to code.
---
## Design Goals
1. **Preserve Tail-Path Matching:** The fast O(1) lookup for bundled corpus must remain the default path
2. **Explicit Over Implicit:** Policy authors must explicitly define matches—no magic auto-aliasing
3. **Cryptographically Verified:** Aliases are part of the signed Trust Pack, tamper-resistant
4. **Zero Dev Team Configuration:** Import a Trust Pack URL, scanning works—no per-team setup
5. **Full Audit Trail:** Every conflict traces back to specific policy, alias pattern, and issuer
6. **Backward Compatible:** Existing Trust Packs without aliases continue working unchanged
---
## Technical Architecture
### Current: Tail-Path Matching
```
┌─────────────────────────────────────────────────────────────┐
│ Scan Flow │
│ │
│ 1. Extractor produces: │
│ concept_path: "code://rust/myapp/tls/cert_verification" │
│ predicate: "enabled" │
│ value: false │
│ │
│ 2. ConceptIndex::lookup() computes key: │
│ key = "myapp/tls::enabled" (last 2 segments) │
│ │
│ 3. Hash table lookup: O(1) │
│ result = index.get("myapp/tls::enabled") │
│ │
│ 4. If match found → conflict detection │
│ If no match → skip (no authoritative source) │
└─────────────────────────────────────────────────────────────┘
```
**Strengths:**
- O(1) constant-time lookups
- Zero configuration required
- Cross-language matching for RFC-aligned extractors
**Limitation:**
- Only works when policy paths and extractor paths share the same final segments
### Extension: Policy Aliases
Policy Aliases add a fallback matching layer that activates only when tail-path matching fails:
```
┌─────────────────────────────────────────────────────────────┐
│ Extended Matching Flow │
│ │
│ 1. Try tail-path match (existing, fast path) │
│ key = make_key(subject, predicate) │
│ if index.contains(key) → return match │
│ │
│ 2. Try policy alias patterns (fallback path) │
│ for alias in trust_pack.policy_aliases: │
│ for pattern in alias.target_patterns: │
│ if glob_match(pattern, subject): │
│ key = make_key(alias.policy_path, predicate) │
│ if index.contains(key) → return match │
│ │
│ 3. No match → no authoritative source for this claim │
└─────────────────────────────────────────────────────────────┘
```
### Matching Algorithm
**Pseudocode:**
```rust
fn lookup_with_policy_aliases(
index: &ConceptIndex,
subject: &str,
predicate: &str,
policy_aliases: &[PolicyAlias],
) -> Option<&Vec<Assertion>> {
// 1. Fast path: direct tail-path match (O(1))
if let Some(result) = index.lookup(subject, predicate) {
return Some(result);
}
// 2. Fallback path: policy alias expansion (O(P × A))
// P = patterns per alias, A = number of aliases
for alias in policy_aliases {
if subject_matches_any_pattern(subject, &alias.target_patterns) {
if let Some(result) = index.lookup(&alias.policy_path, predicate) {
return Some(result);
}
}
}
None
}
fn subject_matches_any_pattern(subject: &str, patterns: &[String]) -> bool {
patterns.iter().any(|pattern| glob_match(pattern, subject))
}
fn glob_match(pattern: &str, subject: &str) -> bool {
// Split both into segments
let pattern_parts: Vec<&str> = pattern.split('/').collect();
let subject_parts: Vec<&str> = subject.split('/').collect();
// Must have same segment count
if pattern_parts.len() != subject_parts.len() {
return false;
}
// Match segment-by-segment; "*" matches any single segment
pattern_parts.iter()
.zip(subject_parts.iter())
.all(|(p, s)| *p == "*" || *p == *s)
}
```
**Step-by-step example:**
```
Input:
subject = "code://rust/backend-api/tls/cert_verification"
predicate = "enabled"
alias = PolicyAlias {
policy_path: "code://standards/tls/cert_verification",
target_patterns: ["code://rust/*/tls/cert_verification"],
}
Step 1: Tail-path match attempt
key = "backend-api/tls::enabled"
index.lookup("backend-api/tls::enabled") → None
Step 2: Alias pattern matching
Pattern: "code://rust/*/tls/cert_verification"
Subject: "code://rust/backend-api/tls/cert_verification"
Segment comparison:
"code:" == "code:" ✓
"" == "" ✓ (after first slash)
"rust" == "rust" ✓
"*" matches "backend-api" ✓ (wildcard)
"tls" == "tls" ✓
"cert_verification" == "cert_verification" ✓
Pattern matches!
Step 3: Lookup using policy_path
key = "tls/cert_verification::enabled"
index.lookup("tls/cert_verification::enabled") → Some([Assertion])
Result: Match found via policy alias
```
---
## Trust Pack Schema Extension
### Current Schema
```rust
#[derive(Archive, Deserialize, Serialize, Debug, Clone)]
#[archive(check_bytes)]
pub struct TrustPack {
pub header: PackHeader,
pub assertions: Vec<Assertion>,
pub aliases: Vec<ConceptAlias>, // Existing: concept-level aliases
pub signature: [u8; 64], // Ed25519 signature
}
pub struct PackHeader {
pub name: String,
pub version: String,
pub issuer_id: [u8; 32], // Ed25519 public key
pub timestamp: u64, // Unix timestamp
}
```
### Extended Schema
```rust
#[derive(Archive, Deserialize, Serialize, Debug, Clone)]
#[archive(check_bytes)]
pub struct TrustPack {
pub header: PackHeader,
pub assertions: Vec<Assertion>,
pub aliases: Vec<ConceptAlias>,
pub policy_aliases: Vec<PolicyAlias>, // NEW: Policy-level aliases
pub signature: [u8; 64],
}
/// Maps policy assertion paths to extractor output patterns.
///
/// Enables enterprise security teams to define standards using logical hierarchies
/// (e.g., "code://standards/tls/*") that match extractor output
/// (e.g., "code://rust/myapp/tls/*").
#[derive(Archive, Deserialize, Serialize, Debug, Clone)]
#[archive(check_bytes)]
pub struct PolicyAlias {
/// The policy path used in assertions.
/// Example: "code://standards/tls/cert_verification"
pub policy_path: String,
/// Glob patterns that should resolve to this policy path.
/// Supports single-segment wildcards (*) only.
///
/// Examples:
/// - "code://rust/*/tls/cert_verification" (any Rust project)
/// - "code://*/myapp/tls/cert_verification" (any language, specific project)
/// - "code://*/*/tls/cert_verification" (any language, any project)
pub target_patterns: Vec<String>,
}
```
**Backward Compatibility:**
```rust
// Deserialization with default for missing field
impl Default for TrustPack {
fn default() -> Self {
TrustPack {
header: PackHeader::default(),
assertions: vec![],
aliases: vec![],
policy_aliases: vec![], // Empty = no policy aliases = current behavior
signature: [0u8; 64],
}
}
}
```
Existing Trust Packs without `policy_aliases` field will deserialize with an empty vector, preserving current behavior.
---
## CLI Interface
### Adding Policy Aliases
```bash
# Add a single alias with multiple target patterns
aphoria policy add-alias \
--pack security-standards.pack \
--policy-path "code://standards/tls/cert_verification" \
--target "code://rust/*/tls/cert_verification" \
--target "code://go/*/tls/cert_verification" \
--target "code://python/*/tls/cert_verification"
```
**Options:**
| Flag | Description |
|------|-------------|
| `--pack <path>` | Path to Trust Pack file |
| `--policy-path <uri>` | Policy assertion path to alias |
| `--target <pattern>` | Glob pattern (can be specified multiple times) |
| `--output <path>` | Output path (default: overwrite input) |
### Listing Policy Aliases
```bash
aphoria policy list-aliases --pack security-standards.pack
```
**Output:**
```
Policy Aliases in "Acme Security Standards" v1.0.0:
1. code://standards/tls/cert_verification
Targets:
- code://rust/*/tls/cert_verification
- code://go/*/tls/cert_verification
- code://python/*/tls/cert_verification
2. code://standards/jwt/audience_validation
Targets:
- code://*/*/jwt/audience_validation
Total: 2 policy aliases
```
### Validating Aliases
```bash
aphoria policy validate-aliases --pack security-standards.pack
```
**Output:**
```
Validating policy aliases...
✓ code://rust/*/tls/cert_verification - valid glob pattern
✓ code://go/*/tls/cert_verification - valid glob pattern
✓ code://python/*/tls/cert_verification - valid glob pattern
⚠ Warning: No assertions found for policy path "code://standards/jwt/audience_validation"
(alias exists but no corresponding assertion)
Validation complete: 3 valid, 0 invalid, 1 warning
```
---
## Enterprise Workflow
### Step 1: Security Team Creates Standards (Golden Repo)
```bash
cd security-standards/
# Create TLS certificate verification requirement
aphoria bless \
--subject "code://standards/tls/cert_verification" \
--predicate "enabled" \
--value true \
--reason "RFC 5246 compliance - TLS certificate verification required"
# Create JWT audience validation requirement
aphoria bless \
--subject "code://standards/jwt/audience_validation" \
--predicate "enabled" \
--value true \
--reason "RFC 7519 compliance - JWT audience claim must be validated"
```
### Step 2: Security Team Adds Policy Aliases
```bash
# Export unsigned pack
aphoria policy export --name "Acme-Security-Standards" --output acme-v1.0.pack
# Add aliases for all supported languages
aphoria policy add-alias \
--pack acme-v1.0.pack \
--policy-path "code://standards/tls/cert_verification" \
--target "code://rust/*/tls/cert_verification" \
--target "code://go/*/tls/cert_verification" \
--target "code://python/*/tls/cert_verification" \
--target "code://java/*/tls/cert_verification"
aphoria policy add-alias \
--pack acme-v1.0.pack \
--policy-path "code://standards/jwt/audience_validation" \
--target "code://*/*/jwt/audience_validation"
```
### Step 3: Security Team Publishes Pack
```bash
# Upload to internal artifact server
aws s3 cp acme-v1.0.pack s3://acme-policies/acme-v1.0.pack --acl private
# Or publish to internal registry
curl -X POST https://policy-registry.acme.com/packs \
-H "Authorization: Bearer $SECURITY_TEAM_TOKEN" \
--data-binary @acme-v1.0.pack
```
### Step 4: Development Team Configures Project
**File: `aphoria.toml`**
```toml
[policies]
sources = [
"https://policy-registry.acme.com/packs/acme-v1.0.pack"
]
# Or using S3 presigned URL
# sources = [
# "s3://acme-policies/acme-v1.0.pack"
# ]
```
That's it. No other configuration needed.
### Step 5: Development Team Scans Code
```bash
aphoria scan --mode persistent
```
**Console Output:**
```
┌─────────────────────────────────────────────────────────────────┐
│ Aphoria Security Scan Report │
├─────────────────────────────────────────────────────────────────┤
│ Project: backend-api │
│ Files: 42 │
│ Claims: 127 │
├─────────────────────────────────────────────────────────────────┤
│ BLOCK (1) │
├─────────────────────────────────────────────────────────────────┤
│ src/main.rs:42 │
│ │
│ code://rust/backend-api/tls/cert_verification │
│ │
│ Code asserts: enabled = false (confidence: 0.95) │
│ Authority: enabled = true (confidence: 1.00) │
│ │
│ Source: Acme-Security-Standards v1.0.0 │
│ Issuer: a1b2c3d4e5f6... │
│ Policy: code://standards/tls/cert_verification │
│ │
│ Matched via policy alias: │
│ Pattern: code://rust/*/tls/cert_verification │
│ │
│ Verdict: BLOCK │
│ Recommendation: Enable TLS certificate verification │
└─────────────────────────────────────────────────────────────────┘
Exit code: 1
```
### Step 6: CI/CD Integration
**GitHub Actions:**
```yaml
name: Security Scan
on: [push, pull_request]
jobs:
aphoria-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Aphoria
run: cargo install aphoria
- name: Run Security Scan
run: aphoria scan --mode persistent --exit-code
# Exit code 1 = BLOCK verdict found → build fails
```
---
## Security Considerations
### Signature Verification
Policy aliases are included in the signed Trust Pack:
```rust
fn sign_trust_pack(pack: &TrustPack, key: &SigningKey) -> [u8; 64] {
// Signature covers ALL fields including policy_aliases
let content = serialize(&TrustPackContent {
header: pack.header.clone(),
assertions: pack.assertions.clone(),
aliases: pack.aliases.clone(),
policy_aliases: pack.policy_aliases.clone(), // Included
});
key.sign(&content).to_bytes()
}
```
**Guarantee:** If anyone tampers with policy aliases, signature verification fails.
### Audit Trail
Every conflict report includes:
1. **Pack Name & Version:** Which Trust Pack triggered the conflict
2. **Issuer ID:** Ed25519 public key of the signing authority
3. **Policy Path:** The canonical policy assertion that was matched
4. **Matched Pattern:** Which glob pattern caused the match
5. **Timestamp:** When the Trust Pack was created
This enables forensic analysis: "Why did this build fail?" → "Because pattern X in pack Y matched code Z."
### Tamper Resistance
```
Trust Pack Integrity Chain:
1. Security team creates assertions in local Episteme store
2. `aphoria policy export` serializes + signs with team's Ed25519 key
3. Pack distributed via any channel (S3, registry, etc.)
4. Dev team's `aphoria scan` verifies signature before using
5. If signature invalid → pack rejected, scan fails with clear error
```
### Privilege Separation
| Actor | Can Do | Cannot Do |
|-------|--------|-----------|
| Security Team | Create assertions, add aliases, sign packs | Modify dev team code |
| Dev Team | Import packs, run scans, acknowledge conflicts | Modify pack contents, bypass policies |
| CI/CD | Run scans, fail builds | Override BLOCK verdicts |
---
## Performance Analysis
### Complexity Analysis
| Operation | Time Complexity | Space Complexity |
|-----------|-----------------|------------------|
| Tail-path match (existing) | O(1) | O(N) where N = assertions |
| Policy alias fallback | O(P × A) | O(A) where A = aliases |
| Total lookup | O(1) + O(P × A) | O(N + A) |
Where:
- P = patterns per alias (typically 3-5)
- A = total number of aliases (typically 10-50)
**Expected Performance:**
- 95% of lookups hit fast path (tail-path match)
- 5% of lookups fall through to alias matching
- Alias matching adds ~0.1ms per lookup (simple string comparison)
### Benchmark Targets
| Metric | Target | Rationale |
|--------|--------|-----------|
| Scan time increase | < 5% | Alias matching should be negligible |
| Memory overhead | < 10 KB per pack | Aliases are small strings |
| Policy download time | < 1s | Packs cached after first download |
### Real-World Estimate
For a typical enterprise deployment:
- 50 policy assertions
- 20 policy aliases
- 5 patterns per alias (100 patterns total)
- 10,000 code claims per scan
**Calculations:**
- Fast path hits: ~9,500 claims (95%)
- Alias fallback: ~500 claims
- Alias comparisons: 500 × 100 = 50,000 string comparisons
- String comparison time: ~1 microsecond each
- Total alias overhead: ~50ms per scan
**Conclusion:** Negligible impact on scan time.
---
## Backward Compatibility
### Migration Path
**No migration required.** The change is purely additive:
1. **Existing Trust Packs:** Deserialize with empty `policy_aliases` vector
2. **Existing Scans:** Empty aliases = skip alias fallback = current behavior
3. **Existing CI/CD:** No changes to configuration or commands
4. **Existing Extractors:** No changes to output format
### Zero-Friction Adoption
| Scenario | Required Changes |
|----------|------------------|
| New enterprise deployment | Add `policy_aliases` to Trust Pack |
| Existing small team | None (bundled corpus works) |
| Existing enterprise with custom pack | Add aliases, re-sign, redistribute |
### Version Negotiation
Trust Packs include a version field in the header:
```rust
pub struct PackHeader {
pub schema_version: u8, // 1 = original, 2 = with policy_aliases
// ...
}
```
Older Aphoria versions encountering schema v2 packs will:
1. Log a warning about unknown field
2. Ignore `policy_aliases` (graceful degradation)
3. Continue with tail-path matching only
---
## Alternative Approaches Considered
### Alternative 1: Normalize Extractor Output
**Idea:** Make extractors output "canonical" paths that match standards.
```rust
// Instead of: "code://rust/myapp/tls/cert_verification"
// Output: "code://standards/tls/cert_verification"
```
**Why rejected:**
- Loses language context (`rust/myapp`) needed for file location
- Breaks existing aliases and observations
- Forces extractors to know about ALL standards
- Violates separation of concerns
### Alternative 2: Flexible Tail-Path Length
**Idea:** Try matching with N=1, N=2, N=3 segments.
```rust
// Try multiple keys
"cert_verification::enabled" // N=1
"tls/cert_verification::enabled" // N=2
"myapp/tls/cert_verification::enabled" // N=3
```
**Why rejected:**
- Ambiguous matches (which key wins?)
- Performance impact (3x lookups)
- Doesn't solve semantic differences
- No explicit control over matching behavior
### Alternative 3: Auto-Discover Aliases
**Idea:** Automatically create aliases during scan when tail-path matches but full path differs.
```rust
// Scan detects potential match, auto-creates alias
if tail_match && !full_match {
auto_alias(claim.concept_path, assertion.subject);
}
```
**Why rejected:**
- Implicit behavior (hard to debug)
- No security team approval (bypasses policy control)
- May create false positives
- Violates "explicit over implicit" principle
**Future consideration:** Could be implemented as suggestions (not automatic), shown in scan output.
---
## Implementation Roadmap
### Phase 1: Schema Extension (Day 1)
1. Add `PolicyAlias` type to `policy.rs`
2. Extend `TrustPack` struct with `policy_aliases` field
3. Update serialization/deserialization
4. Update signature computation to include aliases
5. Add unit tests for schema changes
**Deliverable:** Trust Packs can store and serialize policy aliases.
### Phase 2: Pattern Matching (Day 1-2)
1. Implement `glob_match()` function
2. Add `lookup_with_policy_aliases()` to ConceptIndex
3. Write comprehensive test suite for pattern matching
4. Handle edge cases (empty patterns, invalid syntax)
**Deliverable:** Pattern matching algorithm works correctly.
### Phase 3: Scan Integration (Day 2)
1. Load policy aliases from imported Trust Packs
2. Pass aliases to conflict detection
3. Include alias info in conflict reports
4. Update all output formats (JSON, table, markdown, SARIF)
**Deliverable:** Scans detect conflicts via policy aliases.
### Phase 4: CLI Tooling (Day 3)
1. Implement `policy add-alias` command
2. Implement `policy list-aliases` command
3. Implement `policy validate-aliases` command
4. Update help text and documentation
**Deliverable:** Security teams can manage aliases via CLI.
### Phase 5: Documentation & UAT (Day 3-4)
1. Update user documentation
2. Write enterprise deployment guide
3. Create UAT scenario with real enterprise workflow
4. Validate end-to-end functionality
**Deliverable:** Complete documentation and validated implementation.
---
## Open Questions
### Q1: Should we support recursive wildcards?
**Current proposal:** Single-segment wildcards only (`*`)
```
"code://rust/*/tls/*" ✓ Supported
"code://rust/**/tls" ✗ Not supported (yet)
```
**Trade-off:** Recursive wildcards (`**`) are more flexible but harder to reason about. Start simple, add if needed.
**Decision requested:** Defer recursive wildcards to future enhancement?
### Q2: What happens when multiple aliases match?
**Current proposal:** First match wins (aliases processed in declaration order).
**Alternative:** Most specific match wins (fewer wildcards = higher priority).
**Trade-off:** First-match is simpler but requires security teams to order aliases carefully.
**Decision requested:** First-match or most-specific?
### Q3: Should invalid patterns fail Trust Pack creation?
**Current proposal:** Yesvalidate patterns at creation time, reject invalid glob syntax.
**Alternative:** Warn but allow (lenient), fail at scan time.
**Trade-off:** Fail-fast is better for security teams but may be inconvenient during iteration.
**Decision requested:** Strict validation at creation time?
### Q4: Should we cache pattern match results?
**Current proposal:** Recompute on each lookup (simple, no cache invalidation issues).
**Alternative:** Cache subject policy_path map per scan.
**Trade-off:** Caching improves performance but adds complexity.
**Decision requested:** Defer optimization until benchmarks show need?
---
## Appendix: Example Scenarios
### Scenario A: Multi-Language TLS Enforcement
**Security team creates:**
```bash
aphoria bless \
--subject "code://standards/tls/cert_verification" \
--predicate "enabled" \
--value true
aphoria policy add-alias \
--pack standards.pack \
--policy-path "code://standards/tls/cert_verification" \
--target "code://rust/*/tls/cert_verification" \
--target "code://go/*/tls/cert_verification" \
--target "code://python/*/tls/cert_verification" \
--target "code://java/*/tls/cert_verification" \
--target "code://kotlin/*/tls/cert_verification"
```
**Rust team's code:**
```rust
// src/client.rs
let client = reqwest::Client::builder()
.danger_accept_invalid_certs(true) // Violation!
.build()?;
```
**Extractor output:**
```
concept_path: "code://rust/api-service/tls/cert_verification"
predicate: "enabled"
value: false
```
**Scan result:**
```
BLOCK: TLS cert verification disabled
Policy: code://standards/tls/cert_verification
Matched via: code://rust/*/tls/cert_verification
Source: Acme-Security-Standards v1.0.0
```
---
### Scenario B: Cloud-Specific Rules
**Security team creates:**
```bash
aphoria bless \
--subject "code://vendor/aws/s3/public_access" \
--predicate "blocked" \
--value true \
--reason "S3 buckets must not allow public access"
aphoria policy add-alias \
--pack cloud-rules.pack \
--policy-path "code://vendor/aws/s3/public_access" \
--target "code://*/*/aws/s3/public_access" \
--target "code://*/*/cloud/storage/s3/public"
```
**Dev team's Terraform:**
```hcl
resource "aws_s3_bucket_public_access_block" "example" {
bucket = aws_s3_bucket.example.id
block_public_acls = false # Violation!
}
```
**Scan detects via alias matching.**
---
### Scenario C: Internal Policy Exceptions
**Security team creates exception:**
```bash
# Allow MD5 for specific legacy system
aphoria bless \
--subject "code://internal/exceptions/legacy-auth/md5" \
--predicate "allowed" \
--value true \
--reason "Legacy auth system requires MD5 until migration complete"
aphoria policy add-alias \
--pack exceptions.pack \
--policy-path "code://internal/exceptions/legacy-auth/md5" \
--target "code://rust/legacy-auth-service/crypto/md5" \
--target "code://go/legacy-auth-service/crypto/md5"
```
**Result:** Only the specific legacy service can use MD5; all other services still blocked.
---
## Glossary
| Term | Definition |
|------|------------|
| **Assertion** | A claim about a subject-predicate-object relationship |
| **Trust Pack** | Signed bundle of assertions and aliases for distribution |
| **Policy Alias** | Mapping from policy path to extractor output patterns |
| **Tail-Path Matching** | Algorithm using last 2 path segments for index lookup |
| **Glob Pattern** | String pattern with `*` wildcards for matching paths |
| **Issuer ID** | Ed25519 public key identifying Trust Pack signer |
| **BLOCK Verdict** | Scan result indicating policy violation that should halt build |
---
## References
- [Concept Matching Analysis](../applications/aphoria/docs/architecture/concept-matching-analysis.md)
- [Policy Alias Implementation Guide](../applications/aphoria/docs/architecture/policy-alias-implementation.md)
- [Matching Philosophy](../applications/aphoria/docs/architecture/matching-philosophy.md)
- [Enterprise Validation Scenario](../applications/aphoria/docs/architecture/enterprise-validation.md)
- [UAT: Real-World Policy Source Tracking](../applications/aphoria/uat/2026-02-04-uat-real-world-policy-source.md)