| name | add-secure-resource |
| description | Scaffold a new secure AWS resource module in this aws-cdk-secure-constructs library using the test-first workflow and the established three-level control model (immutable CIS-critical fields, a HIGH tier baseline, and a tighten-only property injector) plus a test-verified CIS compliance report. Use when adding a new resource (e.g. SecureQueue, SecureTable, SecureFunction), creating a new src/resources/<resource>/ module, adding a property injector or blueprint, or writing a CIS compliance report for a construct. |
Add a secure resource module
Use this skill to add a new resource (e.g. SQS, DynamoDB, Lambda) following the
exact conventions used by src/resources/s3-bucket/. Always work test-first.
Read templates.md for copy-paste file skeletons.
Module layout
Every resource is a self-contained module under src/resources/<resource>/:
src/resources/<resource>/
fields.ts # internal: CIS_CRITICAL + TIER_VARIABLE + secureMax helpers
secure-<x>.ts # hardened L3 construct (Secure<X>)
blueprints.ts # property injectors incl. Tiered<X>Defaults (tighten-only)
compliance.ts # <X>Compliance.report() -> ComplianceReport (jsii class static)
index.ts # named re-exports of the three public files
Shared types come from src/core/ (SecurityLevel, SecurityLevels,
ComplianceReport, ComplianceControl, ControlStatus). Do not duplicate them.
Test-first workflow
Copy this checklist and complete it in order. Do not write implementation before
its test exists and fails.
- [ ] 1. Define controls: list CIS-critical (locked) vs tier-variable fields
- [ ] 2. Write compliance.test.ts: assert each ENFORCED control holds under override attempts (RED)
- [ ] 3. Write blueprints.test.ts: tier defaults, tighten-only, CIS re-asserted at LOW (RED)
- [ ] 4. Write secure-<x>.test.ts: default HIGH, CIS enforced, tier behavior (RED)
- [ ] 5. Implement fields.ts, then construct, blueprints, compliance, index (GREEN)
- [ ] 6. Wire the module into src/index.ts + ComplianceRegistry.all()
- [ ] 7. Verify: npm run build && npm test && npm run lint (all clean)
Tests live under test/resources/<resource>/ and import from the package root
(../../../src). Mirror the assertion style in
test/resources/s3-bucket/compliance.test.ts (the report's ENFORCED controls are
iterated and each must have a passing assertion, so the report cannot drift).
Three-level control model (must follow)
- CIS-critical (immutable). Put security-critical props in
CIS_CRITICAL and
apply them last in the construct's resource props and last in every
injector's return. They are never overridable by users or injectors.
- Tier baseline. Operational props vary by
SecurityLevel; the construct
defaults to SecurityLevel.HIGH. Define them in TIER_VARIABLE.
- Tighten-only injector.
Tiered<X>Defaults applies the tier via field-level
secureMax* helpers (never weakens an incoming stronger value) and re-asserts
CIS_CRITICAL. Effective tier = strictest(constructTier, injectorTier).
For every tier-variable field, define a secureMax<Field>(tierValue, incoming)
helper in fields.ts that returns the more secure value.
jsii rules (the build will fail otherwise)
- Public enums, not string-literal union types.
- Public interfaces extend the CDK props type directly; never use
Omit/Partial
in exported types (use them only in internal, non-exported code like fields.ts).
- No exported free functions or free
const. Expose values via class statics
(e.g. <X>Compliance.report()); keep helpers module-private in fields.ts.
- A property injector's
inject must keep the interface signature:
inject(originalProps: any, _context: InjectionContext): any (cast internally to
the props type). Add // eslint-disable-next-line @typescript-eslint/no-explicit-any.
- No namespace re-exports in
src/index.ts; use export * from './resources/<resource>'.
Wire into the public surface
In src/index.ts:
export * from './resources/<resource>';
public static all(): ComplianceReport[] {
return [S3BucketCompliance.report(), <X>Compliance.report()];
}
Verify
npm run build
npm test
npm run lint
npm run test:local-build
If npm run build reports tsconfig.json was not generated by jsii, the
hand-written tsconfig was reintroduced; jsii owns the root tsconfig.json while
Jest uses tsconfig.spec.json.