diff --git a/AUDIT-REPORT.md b/AUDIT-REPORT.md index 864f4a4..c5e2557 100644 --- a/AUDIT-REPORT.md +++ b/AUDIT-REPORT.md @@ -3,7 +3,7 @@ **Date:** 2026-05-27 **Auditor:** Claude Code (6 parallel specialist agents) **Scope:** Full monorepo — API, Web, Mobile, Lambdas, Infrastructure/CI/CD, QA/Testing -**Remediation Status:** Phase 1-5 complete (2026-05-27). All Critical and High findings fixed. 17 Medium findings fixed. CI pipeline runs all 108 tests. Test infrastructure bootstrapped. +**Remediation Status:** Phase 1-6 complete (2026-05-27). All Critical and High findings fixed. 20 Medium findings fixed. CI pipeline runs all 108 tests. Test infrastructure bootstrapped. --- @@ -178,12 +178,13 @@ All items below have been remediated: | ID | Finding | Status | |----|---------|--------| -| INF-M1-M2 | Bedrock wildcard model ARN, AOSS `aoss:*` permissions | | +| INF-M1 | Bedrock wildcard model ARN | **FIXED** — scoped to specific inference profile + foundation model ARN | +| INF-M2 | AOSS `aoss:*` data access permissions | **FIXED** — scoped to specific actions per principal (KB role vs index creator) | | INF-M3-M4 | No Cognito advanced security, Google OAuth not in CDK | | | INF-M5 | No S3 enforceSSL | **FIXED** — `enforceSSL: true` on all 4 buckets | | INF-M6-M7 | No custom domain on CF, no WAF | | | INF-M8 | Workflows pinned to @main | **FIXED** — SHA-pinned across all 3 workflow files | -| INF-M9 | `--require-approval never` locally | | +| INF-M9 | `--require-approval never` locally | **FIXED** — changed to `--require-approval broadening` | --- @@ -269,10 +270,15 @@ Validators tested (36 tests). Lambda handlers tested (19 pytest tests for pdf-ge 48. ~~INF-M5~~ — DONE (enforceSSL on all 4 S3 buckets) 49. ~~INF-M8~~ — DONE (SHA-pinned workflow refs in all 3 workflow files) -### Phase 6 — Remaining (not yet started) +### Phase 6 — Infrastructure Medium Fixes (INF-M1, M2, M9) +50. ~~INF-M1~~ — DONE (Bedrock IAM scoped to specific inference profile ARN) +51. ~~INF-M2~~ — DONE (AOSS data access policy scoped per principal) +52. ~~INF-M9~~ — DONE (`--require-approval broadening` in deploy script) + +### Phase 7 — Remaining (not yet started) - WEB-H1: Token refresh mechanism (requires backend refresh token flow) - Mobile High findings (MOB-H1 through H4): separate release cycle -- Remaining Medium findings: API-M1/M2/M5/M7/M9/M10/M12/M13, WEB-M1/M3/M4/M8/M9/M11/M12, LAM-M2-M4/M6-M7/M9-M14, INF-M1-M4/M6-M7/M9 +- Remaining Medium findings: API-M1/M2/M5/M7/M9/M10/M12/M13, WEB-M1/M3/M4/M8/M9/M11/M12, LAM-M2-M4/M6-M7/M9-M14, INF-M3-M4/M6-M7 - QA-C6: Mobile test coverage --- diff --git a/infra/lib/compute-stack.ts b/infra/lib/compute-stack.ts index 450050f..900636c 100644 --- a/infra/lib/compute-stack.ts +++ b/infra/lib/compute-stack.ts @@ -132,16 +132,61 @@ export class ComputeStack extends cdk.Stack { resources: [ossCollection.attrArn], })); + // Fix: INF-M2 — scope AOSS data access policy permissions (was aoss:* on both + // collection and index). KB role needs read/write for embeddings. Index creator + // needs create/describe for bootstrapping the vector index. const ossDataAccessPolicy = new opensearchserverless.CfnAccessPolicy(this, 'OssDataAccessPolicy', { name: 'proposal-system-kb-access', type: 'data', - policy: JSON.stringify([{ - Rules: [ - { ResourceType: 'collection', Resource: ['collection/proposal-system-kb'], Permission: ['aoss:*'] }, - { ResourceType: 'index', Resource: ['index/proposal-system-kb/*'], Permission: ['aoss:*'] }, - ], - Principal: [kbRole.roleArn, indexCreatorFn.role!.roleArn], - }]), + policy: JSON.stringify([ + { + Description: 'Bedrock KB role — read/write documents and describe collection', + Rules: [ + { + ResourceType: 'collection', + Resource: ['collection/proposal-system-kb'], + Permission: [ + 'aoss:DescribeCollectionItems', + 'aoss:CreateCollectionItems', + 'aoss:UpdateCollectionItems', + ], + }, + { + ResourceType: 'index', + Resource: ['index/proposal-system-kb/*'], + Permission: [ + 'aoss:DescribeIndex', + 'aoss:ReadDocument', + 'aoss:WriteDocument', + ], + }, + ], + Principal: [kbRole.roleArn], + }, + { + Description: 'Index creator Lambda — create and describe index during bootstrap', + Rules: [ + { + ResourceType: 'collection', + Resource: ['collection/proposal-system-kb'], + Permission: [ + 'aoss:DescribeCollectionItems', + 'aoss:CreateCollectionItems', + ], + }, + { + ResourceType: 'index', + Resource: ['index/proposal-system-kb/*'], + Permission: [ + 'aoss:CreateIndex', + 'aoss:DescribeIndex', + 'aoss:WriteDocument', + ], + }, + ], + Principal: [indexCreatorFn.role!.roleArn], + }, + ]), }); ossDataAccessPolicy.addDependency(ossCollection); @@ -354,9 +399,14 @@ export class ComputeStack extends cdk.Stack { internalApiKeySecret.grantRead(suggestionsFunction); // Fix: LAM-C1/INF-H1 — grant Function URL invoke permission for IAM auth apiFunctionUrl.grantInvokeUrl(suggestionsFunction); + // Fix: INF-M1 — scope Bedrock model ARN to the specific inference profile used + // (was wildcard anthropic.claude-*). Lambda MODEL_ID is a cross-region inference profile. suggestionsFunction.addToRolePolicy(new iam.PolicyStatement({ actions: ['bedrock:InvokeModel'], - resources: [`arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-*`], + resources: [ + `arn:aws:bedrock:us-east-1:${this.account}:inference-profile/us.anthropic.claude-sonnet-4-5-20250929-v1:0`, + `arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-sonnet-4-5-20250929-v1:0`, + ], })); suggestionsFunction.addToRolePolicy(new iam.PolicyStatement({ actions: ['bedrock:Retrieve'], @@ -388,9 +438,13 @@ export class ComputeStack extends cdk.Stack { // Fix: LAM-C1/INF-H1 — grant Function URL invoke permission for IAM auth apiFunctionUrl.grantInvokeUrl(pdfExtractFunction); props.uploadsBucket.grantRead(pdfExtractFunction); + // Fix: INF-M1 — scope Bedrock model ARN to the specific inference profile used pdfExtractFunction.addToRolePolicy(new iam.PolicyStatement({ actions: ['bedrock:InvokeModel'], - resources: [`arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-*`], + resources: [ + `arn:aws:bedrock:us-east-1:${this.account}:inference-profile/us.anthropic.claude-sonnet-4-5-20250929-v1:0`, + `arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-sonnet-4-5-20250929-v1:0`, + ], })); // Python Lambda: PDF Generate diff --git a/infra/package.json b/infra/package.json index cfcca9e..99d1a27 100644 --- a/infra/package.json +++ b/infra/package.json @@ -7,7 +7,7 @@ "watch": "tsc -w", "cdk": "cdk", "synth": "cdk synth", - "deploy": "cdk deploy --all --require-approval never" + "deploy": "cdk deploy --all --require-approval broadening" }, "dependencies": { "aws-cdk-lib": "2.257.0",