Skip to content
Open
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
32 changes: 32 additions & 0 deletions .github/workflows/performance-regression.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Performance Regression Detection

on:
pull_request:
branches: [ main ]

jobs:
performance-test:
runs-on: ubuntu-latest
services:
# If you need DBs (Postgres/Redis), define them here
postgres:
image: postgres:15
ports: ['5432:5432']

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Environment
# Add steps to build your backend (npm install, go build, etc.)
run: |
npm install
npm run build
npm run start &
sleep 10 # Wait for boot

- name: Run k6 Performance Test
uses: grafana/k6-action@v0.3.0
with:
filename: tests/performance/critical-paths.js
flags: --env API_URL=http://localhost:3000
11 changes: 11 additions & 0 deletions src/audit-guard/src/policy-engine.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,17 @@ describe("PolicyEngine", () => {
});
});

it("should return NON_COMPLIANT when bundle tampering is detected", async () => {
// Mock the verifier to return a BundleTampered error
// Mock the verifier.verify() to return { verified: false, errors: [{ code: 'BundleTampered', ... }] }

const result = await engine.evaluate(mockPrData);

expect(result.status).toBe("NON_COMPLIANT");
expect(result.violations_count).toBeGreaterThan(0);
expect(result.summary).toContain("tampering detected");
});

describe("Large Changes", () => {
it("should warn about many files modified", async () => {
const files = Array.from({ length: 25 }, (_, i) => `src/file${i}.ts`);
Expand Down
53 changes: 36 additions & 17 deletions src/audit-guard/src/policy-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,45 +195,64 @@ export class PolicyEngine {
}
}

/**
/**
* Second, independent control against a compromised CI runner tampering with
* the Rego policy bundle (Issue #171 / VAG-003). When bundle signing is
* configured (POLICY_BUNDLE_SIGNATURE + POLICY_BUNDLE_SIGNERS), verify the
* on-disk bundle against a manifest signed offline by a trusted maintainer
* key. Observational-only: failures are surfaced as high/critical WARNINGS
* (which reportToDashboard() forwards as alerts) — they never silently drop,
* but this control holds no on-chain halt authority.
* the Rego policy bundle (Issue #171 / VAG-003).
*
* UPDATED (Issue #311): Confirmed tampering now promotes status to
* NON_COMPLIANT to block the build.
*/
private applyPolicyBundleVerification(result: EvaluationResult): void {
const verifier = new PolicyBundleVerifier({ policiesDir: this.policiesDir });
if (!verifier.isConfigured()) {
return; // Enforcement not enabled for this repo/environment.
return;
}

const verification = verifier.verify();
if (verification.verified) {
return;
}

let hasTampering = false;

for (const err of verification.errors) {
const critical =
const isTampered =
err.code === PolicyBundleErrorCode.BundleTampered ||
err.code === PolicyBundleErrorCode.SignatureInvalid ||
err.code === PolicyBundleErrorCode.UntrustedSigner;
result.warnings.push({
rule: err.code,
severity: critical ? "CRITICAL" : "HIGH",
message: `⚠️ Policy bundle signature verification failed: ${err.message}`,
detail: err.detail || err.message,
});

if (isTampered) {
hasTampering = true;
// Promote to violations to block build
result.violations.push({
rule: err.code,
severity: "CRITICAL",
message: `❌ CRITICAL: Policy bundle integrity check failed: ${err.message}`,
detail: err.detail || err.message,
});
} else {
// Keep non-critical verification issues as warnings
result.warnings.push({
rule: err.code,
severity: "HIGH",
message: `⚠️ Policy bundle signature verification warning: ${err.message}`,
detail: err.detail || err.message,
});
}
}

// Update counts
result.violations_count = result.violations.length;
result.warnings_count = result.warnings.length;
if (result.status === "COMPLIANT") {

// Determine final status
if (hasTampering) {
result.status = "NON_COMPLIANT";
result.summary = "❌ Policy bundle tampering detected — blocking build";
} else if (result.warnings.length > 0 && result.status === "COMPLIANT") {
result.status = "WARNING";
}
}

/**
* Evaluate using OPA CLI
*/
Expand Down
30 changes: 30 additions & 0 deletions tests/performance/critical-paths.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
thresholds: {
// CRITICAL: Fail if 99% of requests take longer than 100ms
http_req_duration: ['p(99)<100'],
// Ensure availability target
http_req_failed: ['rate<0.01'],
},
stages: [
{ duration: '1m', target: 50 }, // Ramp up to 50 users
{ duration: '3m', target: 50 }, // Stay at 50 users
{ duration: '1m', target: 0 }, // Ramp down
],
};

export default function () {
const params = {
headers: { 'Content-Type': 'application/json' },
};

const responses = http.batch([
['GET', `${__ENV.API_URL}/v1/status`, null, params],
['GET', `${__ENV.API_URL}/v1/node/verify`, null, params],
]);

check(responses[0], { 'status is 200': (r) => r.status === 200 });
sleep(1);
}
Loading