Commit graph

9 commits

Author SHA1 Message Date
Adam Moussa
211a00a013
chore(security): resolve open dependabot and code scanning alerts (#59)
Some checks failed
Deploy / deploy (push) Has been cancelled
* ci: add least-privilege permissions blocks to workflow callers
Resolves code scanning alerts #3 and #4 (actions/missing-workflow-permissions). Both callable workflows only need contents: read; the dependency-review callable already declares it internally, this caps the caller token to match.

Signed-off-by: Adam Moussa <adam@seahavenind.com>

* build(deps): bump aws-cdk-lib to 2.262.0 to patch brace-expansion

aws-cdk-lib 2.261.0 bundles brace-expansion 5.0.6, which is vulnerable to CVE-2026-13149 (GHSA-3jxr-9vmj-r5cp), an exponential-time DoS in expand(). This was the only path pulling the vulnerable package into the tree. 2.262.0 vendors the patched 5.0.7, resolving Dependabot alert 7.

Because brace-expansion arrives bundled inside the aws-cdk-lib tarball rather than resolved by npm, the aws-cdk-lib bump is the only way to move it.

Signed-off-by: Adam Moussa <adam@seahavenind.com>

* refactor(cdk): drop unreferenced ssm value parameters

fromStringParameterName injects an AWS::SSM::Parameter::Value
CloudFormation parameter to carry the parameter's value, but DoorId
and PhoneIps are only used for grantRead, which builds the ARN from
the name string — so DoorIdParameter and PhoneIpsParameter sat
unreferenced in the template (flagged W2001 by the CloudFormation
validator newly bundled in aws-cdk-lib 2.262.0).

Switching to fromStringParameterAttributes with forceDynamicReference
resolves the value lazily via an SSM dynamic reference, emitting
nothing when unused. Verified the synthesized template is identical
apart from the removed Parameters entries and the CDKMetadata
analytics hash — no IAM or resource changes.

Also re-points the four line-keyed semgrep detect-child-process
suppressions (adjudicated FPs, INFRA-105) to the shifted line
numbers; the findings themselves are unchanged.

Signed-off-by: Adam Moussa <adam@seahavenind.com>

---------

Signed-off-by: Adam Moussa <adam@seahavenind.com>
2026-07-23 20:24:23 +00:00
seahaven-openswe[bot]
3e869ff373 chore: upgrade Lambda runtime nodejs22.x to nodejs24.x (#45) 2026-07-04 01:25:45 -04:00
Adam Moussa
86f078de72 Add CloudWatch Errors alarms to all door-unlock Lambdas (#34)
Physical access control has no error visibility — a Lambda failure
could leave unlock/lockdown/authorizer silently broken. Add ALARM-only
Errors alarms (Sum > 0, 5-min period, NOT_BREACHING) for all four
Lambdas, routed to the cross-stack site-alerts SNS topic encrypted
with alias/seahaven-alarm-topics. No OK/recovery actions per org
convention.

Refs: INFRA-101
2026-06-10 14:38:15 -04:00
Adam Moussa
4265ad90fe Gateway token authorizer + finish CI/CD migration (INFRA-99, INFRA-2) (#32)
* feat: add gateway token authorizer to door-unlock API (INFRA-99)

All three routes (GET /unlock, /lockdown, /lockdown/status) were
AuthorizationType NONE — auth relied solely on each handler checking
the ?token= query param. Add a REQUEST-type HTTP API Lambda authorizer
(door-unlock-api-authorizer) that validates the SAME ?token= value the
Yealink XML Browser keys already send, against the existing
/seahaven/door-unlock/auth-token SSM SecureString, and attach it to all
three routes.

Transparent to the phones: identity source is $request.querystring.token
(exactly what the type-17 XML Browser keys send via GET), simple response
{isAuthorized}, fail-closed, 5-min results cache. Token is cached in
module scope so warm invocations skip SSM.

GET is kept (not switched to POST): the Yealink type-17 XML Browser keys
are GET-only and render the returned Yealink XML — they cannot issue a
POST body or custom headers. POST is therefore deferred to avoid bricking
the door keys.

Handlers retain their own token check as defense-in-depth. Purely
additive change set; no existing Lambda or integration is modified.

* chore: complete CI/CD migration to GitHub Actions (INFRA-2)

GitHub Actions (ci.yaml + deploy.yaml via the Sea Haven reusable
workflows) is the proven deploy path. Remove the now-orphaned
buildspec.yml and update the README CI/CD and architecture sections.

The legacy CodePipeline was already deleted (2026-06-05); the leftover
CodeBuild project seahaven-door-unlock-api-build and its IAM role
seahaven-door-unlock-api-codebuild have now also been decommissioned.
2026-06-08 18:03:30 -04:00
Adam Moussa
565d4af4fd fix: raise unlock Lambda timeout to 20s (#29)
The door-unlock-api-unlock function hit its 10,000ms timeout on
2026-06-05 at 18:00 UTC during a cold start combined with a slow
LenelS2 Elements API call (REPORT: Duration 10000.00 ms, Status:
timeout). A concurrent attempt succeeded in 3639ms, confirming the
call path is healthy but lacks margin under cold-start + slow-API
conditions.

Raise the UnlockHandler timeout from 10s to 20s for additional
headroom. LockdownHandler (15s) and the poller (75s) are unchanged.
2026-06-05 14:31:00 -04:00
Adam Moussa
b0b2444799 Add API access logging (audit Day 3: M-18) (#23)
Access logging to /aws/apigateway/door-unlock-api (90d) on the HTTP API default
stage. Throttling (5 burst / 2 rps) was already present.
2026-06-02 17:42:13 -04:00
Adam Moussa
ccbc98962b Add lockdown mode and CI/CD pipeline (#3)
* Add lockdown profile toggle endpoints with T58W linekey support

Add a new Lambda handler that toggles Elements lockdown profiles
(Bohemia and Ronkonkoma) via the Elements API, with status
verification before and after each toggle. Returns Yealink XML
to control linekey LEDs (green=inactive, red=locked down).

Also brings both Lambda handlers into compliance with system
standards: Node 22.x runtime, arm64 architecture, 60-day log
retention, and kebab-case function names.

* Add lockdown poller Lambda and fix lockdown handler responses

- Add VPC-connected poller Lambda that monitors lockdown status via
  Elements API every 15 seconds (4 polls per 1-min EventBridge schedule)
- Handle Elements API rate limits (429) with retry-after support
- Fix lockdown handler to use TextScreen XML instead of Execute XML
  (Execute shows globe icon on T58W, TextScreen renders properly)
- Fix Elements API status parsing to be case-insensitive
- Trust toggle action instead of re-checking status (eventual consistency)
- Configure push_xml.server = any in T58W template for Push XML support
- Clear action_url.setup_completed (poller replaces boot-time check)
- Update README with lockdown architecture and known LED limitation

Note: T58W line key LED color does not change to reflect lockdown
status. Execute LED commands are transient on the T58W - the phone's
XML Browser key type immediately overrides them.

* Add buildspec for CodePipeline CI/CD

* Update README with CI/CD pipeline details
2026-05-01 18:52:37 -04:00
Adam Moussa
de6e34f827 Fix stack and API naming to follow kebab-case convention
Pin existing CloudFormation stack name via stackName property so
the live stack is not affected. Construct ID and API Gateway name
now follow the org kebab-case standard.
2026-04-28 14:43:48 -04:00
Adam Moussa
12eb0ff9be Add door unlock API — Yealink DSS key triggers LenelS2 Elements TemporaryUnlock via API Gateway + Lambda 2026-04-22 14:36:55 -04:00