# Cross-Attestation Policy Design

## Concept
Rookery policies support `AttestationsFrom` which lets a policy step
reference data from other steps' attestations. This enables correlation
across attestation types that single-attestation policies can't do.

## Policy Architecture

### Multi-Step Policy
```yaml
steps:
  pip-install:
    attestations:
      - command-run (with fileOps, network, syscallEvents)
      - pip-install (packages, PEP 740, static analysis)
      - environment (env vars, OS info)
      - material (file hashes BEFORE install)
      - product (file hashes AFTER install)
      - omnitrail (file metadata snapshots)
    attestationsFrom: []  # self-referencing for cross-attestation Rego
```

### Cross-Attestation Rego Patterns

#### 1. Anti-Forensics Detection (product vs command-run)
```rego
# Files written during install but deleted before product snapshot
deny[msg] if {
    # Files that were written
    written := {w.path | some proc in input.steps["pip-install"]["command-run"].processes;
                         some w in proc.fileOps.writes}
    # Files in product snapshot
    products := {p | some p, _ in input.steps["pip-install"]["product"].products}
    # Written but not in products = cleaned up
    cleaned := written - products
    some f in cleaned
    not startswith(f, "/tmp/")  # temp files are expected to be cleaned
    msg := sprintf("CRITICAL:ANTI_FORENSICS: %s was written during install but removed before completion", [f])
}
```

#### 2. Ptrace Bypass Detection (material+product vs command-run)
```rego
# New files that appeared without a corresponding write syscall
deny[msg] if {
    materials := {m | some m, _ in input.steps["pip-install"]["material"].materials}
    products := {p | some p, _ in input.steps["pip-install"]["product"].products}
    new_files := products - materials
    
    written := {w.path | some proc in input.steps["pip-install"]["command-run"].processes;
                         some w in proc.fileOps.writes}
    opened := {f | some proc in input.steps["pip-install"]["command-run"].processes;
                   some f, _ in proc.openedfiles}
    
    some f in new_files
    not f in written
    not f in opened
    msg := sprintf("CRITICAL:PTRACE_BYPASS: %s appeared after install but was never opened or written by any traced process", [f])
}
```

#### 3. Excess Network Activity (pip-install vs command-run)
```rego
# More TLS connections than packages downloaded
deny[msg] if {
    pkg_count := count(input.steps["pip-install"]["pip-install"].packages)
    tls_conns := count([c | some proc in input.steps["pip-install"]["command-run"].processes;
                            some c in proc.network.connections;
                            c.port == 443; c.family == "AF_INET"])
    # Each package needs ~1 connection (metadata) + 1 (download) = 2
    expected_max := pkg_count * 3  # generous multiplier for mirrors/redirects
    tls_conns > expected_max
    msg := sprintf("HIGH:EXCESS_TLS: %d TLS connections for %d packages (expected max ~%d) — extra connections may indicate data exfiltration", [tls_conns, pkg_count, expected_max])
}
```

#### 4. Credential Exfiltration Pattern (environment + command-run)
```rego
# Process reads environ AND makes network connection = credential harvesting
deny[msg] if {
    some proc in input.steps["pip-install"]["command-run"].processes
    # Read /proc/self/environ
    some f, _ in proc.openedfiles
    contains(f, "/proc/")
    contains(f, "/environ")
    # AND made outbound connection
    some c in proc.network.connections
    c.family == "AF_INET"
    c.port != 53  # not DNS
    msg := sprintf("CRITICAL:CRED_EXFIL_PATTERN: PID %d read process environ AND connected to %s:%d — matches ctx/TeamPCP credential harvesting pattern", [proc.processid, c.address, c.port])
}
```

#### 5. OmniTrail Permission Anomaly
```rego
# Files that changed permissions between omnitrail snapshots
deny[msg] if {
    # OmniTrail records file metadata including permissions
    some f in input.steps["pip-install"]["omnitrail"].files
    f.permissions_changed == true
    f.new_mode & 0o111 != 0  # became executable
    not contains(f.path, "bin/")  # binaries in bin/ are expected
    msg := sprintf("HIGH:PERM_ESCALATION: %s became executable during install (mode: %o)", [f.path, f.new_mode])
}
```

#### 6. Write-then-Delete Detection (command-run self-correlation)
```rego
# Files written to sensitive paths then deleted = evidence destruction
deny[msg] if {
    some proc in input.steps["pip-install"]["command-run"].processes
    some w in proc.fileOps.writes
    some d in proc.fileOps.deletes
    w.path == d.path
    # Sensitive paths
    any([contains(w.path, ".ssh"), contains(w.path, ".aws"),
         contains(w.path, "crontab"), contains(w.path, ".bashrc")])
    msg := sprintf("CRITICAL:WRITE_DELETE: PID %d wrote then deleted %s — evidence destruction of sensitive file modification", [proc.processid, w.path])
}
```

## Implementation Notes

- Cross-attestation requires all attestation types to be in the same collection
  (same cilock run step), which they already are
- The `AttestationsFrom` field in the policy step enables access to other steps
- For self-referencing (within same step), the attestation data is directly in `input`
- OmniTrail attestor needs to be enabled: add `--attestations omnitrail` to cilock run
- Material/Product attestors already run by default

## Priority Order
1. Write-then-delete (command-run self-correlation) — easy, high value
2. Credential exfil pattern (environ + network) — easy, catches ctx/TeamPCP
3. Excess TLS connections (pip-install vs command-run) — medium effort
4. Anti-forensics (product vs command-run) — needs product attestor data
5. Ptrace bypass (material+product vs command-run) — advanced
6. OmniTrail permission anomaly — needs omnitrail attestor enabled
