Skip to content

feat: add guards and use spacecat-shared-utils#6

Merged
solaris007 merged 6 commits intomainfrom
update-dynamo-to-utils
Nov 29, 2023
Merged

feat: add guards and use spacecat-shared-utils#6
solaris007 merged 6 commits intomainfrom
update-dynamo-to-utils

Conversation

@solaris007
Copy link
Copy Markdown
Member

Have dynamo module use guards for its api. The guards now use the spacecat-shared-utils methods.

@solaris007 solaris007 added the enhancement New feature or request label Nov 28, 2023
@solaris007 solaris007 self-assigned this Nov 28, 2023
@github-actions
Copy link
Copy Markdown

This PR will trigger a minor release when merged.

@solaris007 solaris007 merged commit 27143cf into main Nov 29, 2023
@solaris007 solaris007 deleted the update-dynamo-to-utils branch November 29, 2023 08:24
github-actions Bot pushed a commit that referenced this pull request Nov 29, 2023
# [@adobe/spacecat-shared-dynamo-v1.1.0](https://github.com/adobe-rnd/spacecat-shared/compare/@adobe/spacecat-shared-dynamo-v1.0.0...@adobe/spacecat-shared-dynamo-v1.1.0) (2023-11-29)

### Features

* add guards and use spacecat-shared-utils ([#6](#6)) ([27143cf](27143cf))
@solaris007
Copy link
Copy Markdown
Member Author

🎉 This PR is included in version @adobe/spacecat-shared-dynamo-v1.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

github-actions Bot pushed a commit that referenced this pull request Nov 29, 2023
# [@adobe/spacecat-shared-example-v1.1.0](https://github.com/adobe-rnd/spacecat-shared/compare/@adobe/spacecat-shared-example-v1.0.0...@adobe/spacecat-shared-example-v1.1.0) (2023-11-29)

### Features

* add guards and use spacecat-shared-utils ([#6](#6)) ([27143cf](27143cf))
@solaris007
Copy link
Copy Markdown
Member Author

🎉 This PR is included in version @adobe/spacecat-shared-example-v1.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

github-actions Bot pushed a commit that referenced this pull request Nov 29, 2023
# [@adobe/spacecat-shared-utils-v1.1.0](https://github.com/adobe-rnd/spacecat-shared/compare/@adobe/spacecat-shared-utils-v1.0.1...@adobe/spacecat-shared-utils-v1.1.0) (2023-11-29)

### Features

* add guards and use spacecat-shared-utils ([#6](#6)) ([27143cf](27143cf))
@solaris007
Copy link
Copy Markdown
Member Author

🎉 This PR is included in version @adobe/spacecat-shared-utils-v1.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

adobe-bot pushed a commit that referenced this pull request Jan 22, 2024
# 1.0.0 (2024-01-22)

### Bug Fixes

* add code-ql ([312af05](312af05))
* add missing pattern to interface ([#72](#72)) ([0eacbff](0eacbff))
* add package exports to npm module ([#4](#4)) ([7236d40](7236d40))
* allow sorting for get audits for site ([#41](#41)) ([3664c97](3664c97))
* allow update of github URL ([#40](#40)) ([21da989](21da989))
* allow use of index for getItem ([#10](#10)) ([9a984d1](9a984d1))
* audit result scores init, test ([#89](#89)) ([96f829c](96f829c))
* auto-remove undefined values ([#64](#64)) ([ce9abac](ce9abac))
* bogus change to force release ([e77e830](e77e830))
* createdAt test ([#88](#88)) ([ac6a5ba](ac6a5ba))
* **deps:** update aws-sdk-js-v3 monorepo ([#16](#16)) ([e60296a](e60296a))
* **deps:** update aws-sdk-js-v3 monorepo to v3.465.0 ([#19](#19)) ([612c257](612c257))
* **deps:** update aws-sdk-js-v3 monorepo to v3.477.0 ([#68](#68)) ([492913f](492913f))
* **deps:** update dependency uuid to v9 ([#22](#22)) ([456bfe8](456bfe8))
* **deps:** update external fixes ([#71](#71)) ([b9a6679](b9a6679))
* **deps:** update external fixes ([#76](#76)) ([5b74623](5b74623))
* **deps:** update external fixes ([#81](#81)) ([67cf21c](67cf21c))
* **deps:** update external fixes ([#90](#90)) ([df8161e](df8161e))
* distinguish lhs-mobile vs lhs-desktop ([#27](#27)) ([18fd1b1](18fd1b1))
* export getLatestAuditsForSite ([#39](#39)) ([e9c9130](e9c9130))
* export rumapiclient as default ([#52](#52)) ([7c5d2f5](7c5d2f5))
* get audit no query ([#34](#34)) ([8fadd0a](8fadd0a))
* get latest audits with delivery type ([#80](#80)) ([d823773](d823773))
* getSitesByDeliveryType signature ([#78](#78)) ([2b6c0fd](2b6c0fd))
* github org ([02f86c3](02f86c3))
* github semantic plugin config ([db5a14a](db5a14a))
* github token reference ([8ac46cf](8ac46cf))
* GSI sort key when error ([#62](#62)) ([dbb6a91](dbb6a91))
* include audit ref and audited at ([#75](#75)) ([e573c90](e573c90))
* initialize scores as an empty object (SITES-18417) ([b43b96d](b43b96d))
* initialize scores as an empty object (SITES-18417) ([#87](#87)) ([eb38e32](eb38e32))
* key validation ([#7](#7)) ([4283e14](4283e14))
* latest-audits sort key ([#33](#33)) ([21dc14e](21dc14e))
* make RUMOptions optional ([6c2825b](6c2825b))
* missing module releaserc ([0ec70ba](0ec70ba))
* move to main.yml ([89a8c69](89a8c69))
* no undefined for putItem ([#43](#43)) ([283f229](283f229))
* npm token (again) ([9934572](9934572))
* npm token renovate ([b6656e7](b6656e7))
* npmToken for renovate ([155a5f3](155a5f3))
* package name to "adobe" ([475434e](475434e))
* pass ascending param ([#42](#42)) ([930ae6b](930ae6b))
* re-set node 20 ([ef24765](ef24765))
* reduce log output of putitem ([#31](#31)) ([29d1496](29d1496))
* remove .keep ([4f9319f](4f9319f))
* remove unneeded import (force release) ([49964f9](49964f9))
* remove unsupported codeql workflow ([467bd3b](467bd3b))
* rename circle ci ([c12906e](c12906e))
* rename NPM token ([fb23bf1](fb23bf1))
* renovate ([1a16980](1a16980))
* repo reference ([881487d](881487d))
* roll-back esm monorepo ([ab77518](ab77518))
* roll-back node 20 for github workflow ([876e26c](876e26c))
* rollback test change for node 18 ([ff981fb](ff981fb))
* rum domain key env var ([b52ead5](b52ead5))
* semantic-release scripts ([6078334](6078334))
* set default organization ([#92](#92)) ([ac7e70c](ac7e70c))
* set github_token correctly ([cf6a8aa](cf6a8aa))
* set package version to semantic, remove dev deps ([bf62c5f](bf62c5f))
* set pre-commit hook executable ([3ce9a6c](3ce9a6c))
* set to semantic-release versioning ([9209799](9209799))
* sort order sites with latest audits ([#46](#46)) ([8da2bf1](8da2bf1))
* switch defaults to dev (force release) ([b85d54c](b85d54c))
* type def / jsdoc ([#61](#61)) ([078f9e6](078f9e6))
* typo ([9167cf3](9167cf3))
* update dynamo client ([#65](#65)) ([cc09041](cc09041))
* update node to lts/20, semantic release, misc ([#91](#91)) ([099662a](099662a))
* use correct doc client ([#9](#9)) ([d052b16](d052b16))
* use getItem for latest audit ([#35](#35)) ([6e4a87e](6e4a87e))
* use new aem datadesk ui for the backlinks ([#79](#79)) ([526b69c](526b69c))
* variouss ([ea9d44f](ea9d44f))
* wrap scores ([#28](#28)) ([4733a93](4733a93))

### Features

* add audit config ([#59](#59)) ([f851862](f851862))
* add broken-backlinks audit type (SITES-18417) ([#86](#86)) ([b16c366](b16c366))
* add data access module ([#11](#11)) ([cdbfff3](cdbfff3))
* add dynamo and utils modules ([#3](#3)) ([5e2e605](5e2e605))
* add guards and use spacecat-shared-utils ([#6](#6)) ([27143cf](27143cf))
* add isArray function ([eeb45a6](eeb45a6))
* add rum api calls to shared ([56cccd0](56cccd0))
* add support for 404 report backlink ([0d622de](0d622de))
* allow configuration from ctx / add missing fields ([#24](#24)) ([6959f89](6959f89))
* data model for organizations ([944be83](944be83))
* http utils package ([#51](#51)) ([84cd91a](84cd91a))
* http-utils functions ([#49](#49)) ([20e98fa](20e98fa))
* introduce getSiteByID ([#36](#36)) ([5677f76](5677f76))
* resolve secrets name ([#44](#44)) ([8c7604d](8c7604d))
* rum api client ([#48](#48)) ([ccfa187](ccfa187))
* set isLiveToggledAt ([#85](#85)) ([cefc093](cefc093))
* site delivery type ([#77](#77)) ([005bc38](005bc38))
* store previous latest audit result ([#74](#74)) ([4663c43](4663c43))
* test ([bd3cc5d](bd3cc5d))
* update audit config ([#63](#63)) ([00a468e](00a468e))

### Reverts

* Revert "fix: allow use of index for getItem (#10)" (#15) ([ad03176](ad03176)), closes [#10](#10) [#15](#15)
adobe-bot pushed a commit that referenced this pull request Jan 22, 2024
# 1.0.0 (2024-01-22)

### Bug Fixes

* add code-ql ([312af05](312af05))
* add missing pattern to interface ([#72](#72)) ([0eacbff](0eacbff))
* add package exports to npm module ([#4](#4)) ([7236d40](7236d40))
* allow sorting for get audits for site ([#41](#41)) ([3664c97](3664c97))
* allow update of github URL ([#40](#40)) ([21da989](21da989))
* allow use of index for getItem ([#10](#10)) ([9a984d1](9a984d1))
* audit result scores init, test ([#89](#89)) ([96f829c](96f829c))
* auto-remove undefined values ([#64](#64)) ([ce9abac](ce9abac))
* bogus change to force release ([e77e830](e77e830))
* createdAt test ([#88](#88)) ([ac6a5ba](ac6a5ba))
* **deps:** update aws-sdk-js-v3 monorepo ([#16](#16)) ([e60296a](e60296a))
* **deps:** update aws-sdk-js-v3 monorepo to v3.465.0 ([#19](#19)) ([612c257](612c257))
* **deps:** update aws-sdk-js-v3 monorepo to v3.477.0 ([#68](#68)) ([492913f](492913f))
* **deps:** update dependency uuid to v9 ([#22](#22)) ([456bfe8](456bfe8))
* **deps:** update external fixes ([#71](#71)) ([b9a6679](b9a6679))
* **deps:** update external fixes ([#76](#76)) ([5b74623](5b74623))
* **deps:** update external fixes ([#81](#81)) ([67cf21c](67cf21c))
* **deps:** update external fixes ([#90](#90)) ([df8161e](df8161e))
* distinguish lhs-mobile vs lhs-desktop ([#27](#27)) ([18fd1b1](18fd1b1))
* export getLatestAuditsForSite ([#39](#39)) ([e9c9130](e9c9130))
* export rumapiclient as default ([#52](#52)) ([7c5d2f5](7c5d2f5))
* get audit no query ([#34](#34)) ([8fadd0a](8fadd0a))
* get latest audits with delivery type ([#80](#80)) ([d823773](d823773))
* getSitesByDeliveryType signature ([#78](#78)) ([2b6c0fd](2b6c0fd))
* github org ([02f86c3](02f86c3))
* github semantic plugin config ([db5a14a](db5a14a))
* github token reference ([8ac46cf](8ac46cf))
* GSI sort key when error ([#62](#62)) ([dbb6a91](dbb6a91))
* include audit ref and audited at ([#75](#75)) ([e573c90](e573c90))
* include sites without latest audits ([#45](#45)) ([b843190](b843190))
* initialize scores as an empty object (SITES-18417) ([b43b96d](b43b96d))
* initialize scores as an empty object (SITES-18417) ([#87](#87)) ([eb38e32](eb38e32))
* key validation ([#7](#7)) ([4283e14](4283e14))
* latest-audits sort key ([#33](#33)) ([21dc14e](21dc14e))
* make RUMOptions optional ([6c2825b](6c2825b))
* missing module releaserc ([0ec70ba](0ec70ba))
* move to main.yml ([89a8c69](89a8c69))
* no undefined for putItem ([#43](#43)) ([283f229](283f229))
* npm token (again) ([9934572](9934572))
* npm token renovate ([b6656e7](b6656e7))
* npmToken for renovate ([155a5f3](155a5f3))
* package name to "adobe" ([475434e](475434e))
* pass ascending param ([#42](#42)) ([930ae6b](930ae6b))
* re-set node 20 ([ef24765](ef24765))
* reduce log output of putitem ([#31](#31)) ([29d1496](29d1496))
* remove .keep ([4f9319f](4f9319f))
* remove unneeded import (force release) ([49964f9](49964f9))
* remove unsupported codeql workflow ([467bd3b](467bd3b))
* rename circle ci ([c12906e](c12906e))
* rename NPM token ([fb23bf1](fb23bf1))
* renovate ([1a16980](1a16980))
* repo reference ([881487d](881487d))
* roll-back esm monorepo ([ab77518](ab77518))
* roll-back node 20 for github workflow ([876e26c](876e26c))
* rollback test change for node 18 ([ff981fb](ff981fb))
* rum domain key env var ([b52ead5](b52ead5))
* semantic-release scripts ([6078334](6078334))
* set default organization ([#92](#92)) ([ac7e70c](ac7e70c))
* set github_token correctly ([cf6a8aa](cf6a8aa))
* set latest version for semantic ([#94](#94)) ([932e11f](932e11f))
* set package version to semantic, remove dev deps ([bf62c5f](bf62c5f))
* set pre-commit hook executable ([3ce9a6c](3ce9a6c))
* set to semantic-release versioning ([9209799](9209799))
* sort order sites with latest audits ([#46](#46)) ([8da2bf1](8da2bf1))
* switch defaults to dev (force release) ([b85d54c](b85d54c))
* type def / jsdoc ([#61](#61)) ([078f9e6](078f9e6))
* typo ([9167cf3](9167cf3))
* update dynamo client ([#65](#65)) ([cc09041](cc09041))
* update node to lts/20, semantic release, misc ([#91](#91)) ([099662a](099662a))
* update readme (force release) ([#95](#95)) ([8dd61cd](8dd61cd))
* update readme (test release ([#93](#93)) ([d5142d0](d5142d0))
* use correct doc client ([#9](#9)) ([d052b16](d052b16))
* use getItem for latest audit ([#35](#35)) ([6e4a87e](6e4a87e))
* use new aem datadesk ui for the backlinks ([#79](#79)) ([526b69c](526b69c))
* variouss ([ea9d44f](ea9d44f))
* wrap scores ([#28](#28)) ([4733a93](4733a93))

### Features

* add audit config ([#59](#59)) ([f851862](f851862))
* add broken-backlinks audit type (SITES-18417) ([#86](#86)) ([b16c366](b16c366))
* add data access module ([#11](#11)) ([cdbfff3](cdbfff3))
* add dynamo and utils modules ([#3](#3)) ([5e2e605](5e2e605))
* add guards and use spacecat-shared-utils ([#6](#6)) ([27143cf](27143cf))
* add isArray function ([eeb45a6](eeb45a6))
* add rum api calls to shared ([56cccd0](56cccd0))
* add support for 404 report backlink ([0d622de](0d622de))
* allow configuration from ctx / add missing fields ([#24](#24)) ([6959f89](6959f89))
* data model for organizations ([944be83](944be83))
* http utils package ([#51](#51)) ([84cd91a](84cd91a))
* http-utils functions ([#49](#49)) ([20e98fa](20e98fa))
* introduce getSiteByID ([#36](#36)) ([5677f76](5677f76))
* resolve secrets name ([#44](#44)) ([8c7604d](8c7604d))
* rum api client ([#48](#48)) ([ccfa187](ccfa187))
* set isLiveToggledAt ([#85](#85)) ([cefc093](cefc093))
* site delivery type ([#77](#77)) ([005bc38](005bc38))
* store previous latest audit result ([#74](#74)) ([4663c43](4663c43))
* test ([bd3cc5d](bd3cc5d))
* update audit config ([#63](#63)) ([00a468e](00a468e))

### Reverts

* Revert "fix: allow use of index for getItem (#10)" (#15) ([ad03176](ad03176)), closes [#10](#10) [#15](#15)
solaris007 added a commit that referenced this pull request Feb 19, 2026
…#1364)

## Why

SpaceCat Lambda functions currently use `@adobe/helix-shared-secrets` to
load secrets from AWS Secrets Manager. This couples secret management to
AWS administrative access - CAMP's 3 immutable roles (admin, power user,
read only) don't allow creating a restricted Secrets Manager-only role,
so anyone with AWS admin access can read all secrets. Following the S3
credentials leak incident (MSI0001036), moving secrets to HashiCorp
Vault was identified as remediation track #6: Vault provides a separate
auth boundary with granular ACLs, audit trail, and short-lived
credentials, fully de-coupled from AWS access.

This package enables the migration - services switch from `helixSecrets`
to `vaultSecrets` in their middleware chain with no other code changes.

## What

Adds `@adobe/spacecat-shared-vault-secrets` - a drop-in replacement for
`@adobe/helix-shared-secrets` that loads secrets from Vault instead of
AWS Secrets Manager. Same `.with()` middleware interface, same caching
strategy, different backend.

1. On cold start, reads bootstrap config from AWS Secrets Manager at
`/mysticat/bootstrap/{service-name}` (auto-resolved from
`ctx.func.name`) to get per-service Vault AppRole credentials
2. Authenticates to Vault via AppRole (role_id + secret_id)
3. Reads secrets from `dx_mysticat/{environment}/{service-name}` (KV V2)
4. Merges into `context.env` and `process.env`
5. Two-tier caching: 60s metadata check, 1h hard expiration

**Per-service credential isolation:** Each service gets its own AppRole,
its own policy, and its own bootstrap secret. A compromised service
credential can only read that service's secrets.

**HTTP call budget:** Cold start = 3 calls (AWS SM + AppRole login +
secret read). Warm invocation within 60s = 0 calls. Past 60s = 1 call
(metadata). Secret rotation = 2 calls (metadata + read).

### Files

| File | Purpose |
|------|---------
| `src/vault-client.js` | Vault HTTP client with private class fields
(AppRole login, KV V2 read, metadata, token renewal) |
| `src/bootstrap.js` | AWS Secrets Manager bootstrap loader
(aws4-signed, no SDK dependency) |
| `src/vault-secrets-wrapper.js` | Middleware wrapper (two-tier caching,
path resolution, concurrency lock, env merge) |
| `src/index.js` / `src/index.d.ts` | Exports and TypeScript
declarations |

### Usage

```js
import wrap from '@adobe/helix-shared-wrap';
import vaultSecrets from '@adobe/spacecat-shared-vault-secrets';

// Zero-config: bootstrapPath and Vault path both auto-resolve from ctx.func.name
export const main = wrap(run)
  .with(vaultSecrets)
  .with(helixStatus);
```

### Prerequisites

Each service in each AWS account (dev/stage/prod) needs:

1. **Per-service AppRole** in Vault - provisioned via
`cst-vault/vault_policies` PRs (done)

2. **Per-service bootstrap secret** in AWS Secrets Manager at
`/mysticat/bootstrap/{service-name}`:

```json
{
  "role_id": "<service-specific-approle-role-id>",
  "secret_id": "<service-specific-secret-id>",
  "vault_addr": "https://vault-amer.adobe.net",
  "mount_point": "dx_mysticat",
  "environment": "dev"
}
```

3. **VPC configuration** - Lambda must run in the SpaceCat VPC (private
subnets with NAT gateway). Vault rejects AppRole login from non-Adobe
IPs with HTTP 403.

4. **IAM permissions** - Lambda role needs
`secretsmanager:GetSecretValue` on `/mysticat/bootstrap/*`. Three IAM
policies updated in spacecat-infrastructure PR #336.

See the [package
README](packages/spacecat-shared-vault-secrets/README.md) for full setup
details, secret-id rotation procedure, and error reference.

## Test plan

- [x] 54 unit tests passing (including 3 new bootstrapPath
auto-resolution tests)
- [x] 100% statement/function/line coverage
- [x] Two rounds of crew review (security, architecture, code quality) -
all must-fix items addressed
- [x] Lint clean
- [x] E2E validated on real Lambda (SM bootstrap -> AppRole auth ->
Vault KV read)
- [x] CI passes
ekremney added a commit that referenced this pull request Mar 10, 2026
…che and keepAlive

Addresses PR review items #4-#7:

- **#4 (Response cache)**: @adobe/fetch caches GET responses by default (100MB LRU).
  PostgREST and Vault GET responses would be cached, causing stale reads after
  writes. Fix: use noCache/keepAliveNoCache contexts to disable response caching.

- **#5 (Dependency weight)**: vault-secrets now imports @adobe/fetch directly
  instead of @adobe/spacecat-shared-utils, avoiding heavy transitive deps
  (cheerio, aws-xray-sdk, zod, etc.) in a security-critical package.

- **#6 (keepAlive: false)**: @adobe/fetch's default h2() context sets keepAlive: false
  for h1 on Node 19+. PostgREST is behind a plain HTTP ALB, so all requests use h1.
  Fix: data-access uses keepAliveNoCache() which forces h1 with keepAlive: true.
  Vault uses noCache() which enables h2 for HTTPS targets.

- HELIX_FETCH_FORCE_HTTP1 fallback: both packages use h1NoCache() in tests
  for nock compatibility, matching the established pattern from shared-utils.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants