Repository navigation
fix(ci): get Frigg CI green on next - #710
Conversation
mongodb-memory-server 8.x defaults to MongoDB 5.0.19, whose only Linux builds target Ubuntu 20.04 and link against OpenSSL 1.1. GitHub's ubuntu-latest is now 24.04, which ships OpenSSL 3 only, so every core run died in globalSetup with `StdoutInstanceError: ... "libcrypto.so.1.1"` and no core suite ran. mongodb-memory-server 11 resolves native ubuntu2404 builds for MongoDB 8.x. TestMongo now pins the binary (8.0.17) explicitly instead of inheriting the library default, so a future library bump can't silently change the server version; MONGOMS_VERSION still overrides it. The lockfile change is limited to the mongodb-memory-server subtree (and its mongodb driver/bson); unrelated `peer` flag churn from a different npm version was left out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
Core's jest globalSetup delegated to @friggframework/test, which starts a MongoMemoryServer and exports MONGO_URI before any suite runs. Nothing in the default core suite talks to that server (repository tests mock Prisma; prisma.test.js only checks env handling), yet when the binary couldn't start the whole core suite (~200 files) was skipped. Unit suites must not need a database. The core setup now only applies the STAGE=dev default and restores the environment on teardown. TestMongo and @friggframework/test's own globalSetup are unchanged for apps that opt in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
…st:db` Three encryption suites connect to a live MongoDB replica set or PostgreSQL through generated Prisma clients instead of mocking Prisma: mongo-decryption-fix-verification, postgres-decryption-fix-verification and postgres-relation-decryption. In the default run they failed with "Cannot find Prisma client" (or would have needed a database), so they are now DB integration tests: - renamed to *.db.test.js and ignored by the default jest config; - run by `npm run test:db` (jest.db.config.js, runInBand); - connection strings come from FRIGG_TEST_MONGODB_URL / FRIGG_TEST_POSTGRES_URL (defaults unchanged), so one run can reach both databases without fighting over DATABASE_URL. All 16 tests pass against mongo:8.0 (replica set) and postgres:16. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
loadModuleEncryptionSchemas required '../integrations/utils/map-integration-dto'
from database/encryption/, which resolves to a path that doesn't exist.
loadCustomEncryptionSchema swallows errors at debug level, so module-level
`encryption.credentialFields` declarations were silently never registered
and those credential fields were stored unencrypted. The tests for this
(never run in CI because core's globalSetup failed) caught it.
With the path fixed, two more problems surfaced and are fixed here:
- A module listing a field the core schema already encrypts (e.g.
`api_key`) failed validation ("Cannot override core encrypted field"),
dropping every field from every module. Core fields are now filtered out.
- registerCustomSchema replaces the custom schema, so module fields would
have wiped the app's own `encryption.schema`. Module fields are now merged
into the existing custom schema.
Integrations without `Definition.modules` are skipped instead of throwing.
Values already stored in plaintext still read back: decryption passes
through values that aren't in the encrypted format.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
9d746f1 (feat(encryption): add API key encryption) added data.api_key, data.apiKey, data.API_KEY_VALUE, data.password and data.client_secret to CORE_ENCRYPTION_SCHEMA.Credential on purpose; this assertion still listed only the three OAuth token fields. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
… format DocumentDBEncryptionService only encrypts/decrypts values it recognises as Cryptor envelopes (four base64 parts, > 50 chars) and only for fields in the schema registry. The test's mock cryptor emitted "encrypted:<value>" and the suite assumed User.username was encrypted without registering it, so 11 assertions failed once core tests ran again. The mock now emits a keyId:iv:ciphertext:encryptedKey envelope (plaintext as the base64 ciphertext) and the suite registers User.username as a custom field, the way an app opts in via appDefinition.encryption.schema. Assertions are otherwise unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
Three assertions tested the mocks rather than the repository: - "stores encrypted mapping": the find mock always returned a document, so upsertMapping took the update path and never inserted. The first lookup now returns no match. - "preserves other fields during update": read `command.update.$set`, but `update` is the collection name; the update document is `command.updates[0].u` (see documentdb-utils updateOne). - "corrupted ciphertext": 'keyId:invalid-iv:...' isn't base64, so the service correctly treats it as legacy plaintext and returns it. The test now corrupts a real envelope (unknown key id) and expects the throw. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
aes-256-ctr needs a 32-byte key. The test's data key
('test-key-32-bytes-long-exactly') and AES_KEY
('test-aes-key-32-bytes-long-123') are 30 bytes, so createCipheriv threw
"Invalid key length". The "key not found" case passed a 3-part string, so
decrypt failed on the missing 4th part before it reached the key lookup.
Both fixtures now match the real formats; Cryptor itself is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
…ests
The x-frigg-headers and adopter-JWT use cases throw
Boom.badRequest(<explanation>) / Boom.notImplemented(<explanation>). The
tests expected the *default* message ("Bad Request" / "Not Implemented")
as a substring, which only holds when no message is given, so they failed
on every Node version. They now assert output.statusCode (400 / 501),
which is what the tests are named for; the message-content tests already
exist alongside.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
…, type } API 1829e7d renamed externalEntityId to externalId and 29890e5 made findIntegrationContextByExternalEntityId take { externalId, type } and pick the integration by config.type (a7bacab) via the entity binding (326f2a7), dropping the ENTITY_USER_NOT_FOUND path. The use-case and command tests still passed { externalEntityId } and expected the old error codes. They now cover EXTERNAL_ID_REQUIRED, TYPE_REQUIRED, ENTITY_NOT_FOUND, INTEGRATION_NOT_FOUND (no integration of that type on the entity) and the success path. The commands README examples were still positional and are updated to match. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
batchSend reused one buffer for every SendMessageBatchCommand and cleared it in place with splice after each send. Every command therefore pointed at the same array, so after the loop all earlier commands' Entries held the final partial batch. The request had already gone out, so delivery was correct, but anything holding the command (SDK middleware, retries, the test's aws-sdk-client-mock recorder) saw the wrong entries; the "10 + 10 + 5" test failed with 5/5/5. Each full batch is now spliced out into its own array. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
2ef107f (feat(database): add DocumentDB support) made documentdb a valid dbType and the message "dbType must be postgresql, mongodb, or documentdb"; the test still matched the two-database wording. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
The postgres and mongodb "should measure actual response time" tests slept 30/50 ms with setTimeout and asserted the measured time was >= the delay. Timers can fire a millisecond early relative to Date.now() (seen locally: 29 ms), and loaded runners can blow the upper bound. The tests now stub Date.now() around an immediately-resolving ping and assert the exact difference, which is what pingDatabase computes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
QueuerUtil moved to @aws-sdk/client-sqs, but this test still mocked `aws-sdk` (v2) SQS, so every queueing step made a real SQSClient call and failed with "Could not load credentials from any providers". It now uses aws-sdk-client-mock on SQSClient (as queuer-util.test.js does) and reads the SendMessageCommand inputs. Two expectations were also stale: - The default ON_WEBHOOK handler no longer logs "Webhook received:" (debug logging was removed in b74f21e); it's a documented no-op, so the test asserts dispatch resolves. - The fixture's onWebhookReceived passed `req.params.integrationId` through as undefined; it now normalises to null like the base handler, which is what "webhooks without integration ID" checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
The ADR-048 require-graph probe reports CLEAN/DIRTY on the child's stderr. On Node 22, requiring core's index emits a DEP0040 (punycode) deprecation warning on stderr too, so the assertion saw "CLEAN(node:…) [DEP0040] …" and failed on the 22.x leg only. The probe now runs the child with --no-warnings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
TestMongo is now opt-in (core no longer starts it), so nothing in the default run would notice if the pinned binary stopped downloading or starting. mongodb.db.test.js starts it and checks MONGO_URI accepts a connection. It follows the same convention as core: `*.db.test.js` is excluded from `npm test` and run by `npm run test:db` (the CI DB job). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
`next` is where PRs land and pre-releases are cut from, but CI only ran on pushes to main, so next itself never had a status of its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
2.0.1 supports Node 22 and 24, so CI covers both. fail-fast is off so a failure on one line still reports the other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
- fetch-depth: 0 was there for super-linter, which this workflow no longer runs; the full fetch pulled thousands of release tags (~2k lines of log) on every run. Default shallow checkout instead. - The hand-rolled ~/.npm cache is what `actions/setup-node` `cache: npm` does, keyed on the lockfile. - `npm run use:npm` reinstalled npm globally to satisfy engines.npm ">=10"; Node 22 and 24 already ship npm >= 10. - A newer push to the same ref cancels the in-flight run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
The build job ran `npm run lint:fix --workspaces` and then git-auto-commit-action pushed "Apply lint auto-fixes" to the branch. A bot must not push to PR branches (it rewrites contributors' branches, and its commits don't re-trigger CI, so they land untested), and it only ran after tests passed, which they never did. Lint is now its own job: `prettier --check` + `eslint` in each package that defines lint:fix, with no writes. The step is continue-on-error because the existing backlog is large (core alone: ~390 files need prettier, 96 eslint errors); the job shows the findings without blocking merges. Flip it to blocking once the backlog is cleared. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
Real-database suites are now `*.db.test.js`, excluded from test:all and run by `npm run test:db`. This job provides what they need: - MongoDB 8.0 started as a single-node replica set (Prisma requires one for MongoDB writes; service containers can't pass --replSet); - a postgres:16 service, with the prisma-postgresql migrations applied; - generated Prisma clients; - a cache for the mongodb-memory-server binary used by TestMongo's smoke test (MONGOMS_DOWNLOAD_DIR points it at the cached path). It runs in parallel with the unit matrix. The Postgres service is also what the tenant-isolation suite (FRIGG_TEST_POSTGRES_URL) needs when it lands on next. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
test-cli.yml failed on every run: it cd's into packages/frigg-cli, which moved to packages/devtools/frigg-cli, and its matrix still tested Node 18/20/21, which 2.0.1 doesn't support. What it ran: - unit/integration tests and coverage: already run by devtools' jest in test:all (frigg-cli/__tests__), so dropped here; - test:e2e / test:unit / test:integration / test:coverage scripts: no longer exist in the CLI package; - `frigg <command> --help` checks: kept, as a step in the build job, for every current command; - Windows/macOS legs: dropped. Nothing else in CI covers them and they never ran green; re-add a targeted OS matrix if cross-platform CLI support becomes a requirement; - Codecov upload with fail_ci_if_error and an 85% coverage gate: dropped (no token configured, gate never met). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
integration-repository-entities-parity and integration-mapping-repository-query-parity run every adapter (MongoDB, DocumentDB on MongoDB, PostgreSQL) through the same cases, but only when their *_PARITY_* URLs are set, which no CI job did; in test:all they showed up as 476 skipped tests. They are renamed to *.db.test.js (still env-gated) and the DB job sets their URLs, so they now run on every PR: 1,422 tests, green locally against mongo:8.0 (replica set) and postgres:16. These are the seed of per-port repository contract tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
VpcBuilder's EXTERNAL security-group branch read decision.physicalId, which createExternalDecision sets to the first ID only (the full list is in physicalIds), so all but the first of vpc.securityGroupIds were silently dropped from the Lambda VpcConfig. Use physicalIds when present. Covered by the composer test's use-existing security-group case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
…'managed' warnIgnoredOptions() tells the user that vpc.management, subnets.management, natGateway.management and shareAcrossStages are ignored in managed mode, but translateLegacyConfig still applied them. With managed + isolated and no VPC in the stack, a leftover vpc.management flipped ownership back to 'auto' and the build failed with "VPC discovery failed: No VPC found". The four options are now applied only outside managed mode; natGateway.id handling is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
…ec.js
devtools had no jest config, so Jest's default testMatch treated every
file under __tests__/ as a suite: six fixture/helper modules
(infrastructure/__tests__/{fixtures,helpers}, frigg-cli/__tests__/utils)
failed with "must contain at least one test". It also collected
management-ui's Vitest/JSX suites, which need their own runner and
dependencies (management-ui is not an npm workspace, so npm ci never
installs them). management-ui and the vendored Prisma layer are ignored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
… never build the Prisma layer or call AWS - A composer test spied fs.existsSync to return false and failed before mockRestore(), so every later test saw no .build-complete marker and ensurePrismaLayerExists() ran a real npm install into the tracked layers/prisma (~40 s, dirty tree). template-generation had no mocks and ran real AWS discovery. Both now stub prisma-layer-manager and gatherDiscoveredResources, as scaffold-default-infrastructure.test.js already does; the suites take under a second. - infrastructure-composer.test.js still targeted the pre-refactor monolith (7b36f0f): it required the deleted aws-discovery module and asserted old logical IDs (VPCEndpointS3, FriggNATRoute), the jetpack/kms-grants plugins, a manual dbMigrate function (replaced in 3bae110) and composer-thrown validation messages. It now asserts the current IDs (FriggS3VPCEndpoint, FriggPrivateRoute, FriggVPCEndpointSecurityGroup), the KMS env-var fallback, the migration router/worker pipeline and the orchestrator's validation flow. - 15 tests were removed because their behaviour moved to a builder and is covered there: NAT placement/management (vpc-builder.test.js, vpc-resolver.test.js), discovery gating (resource-discovery.test.js), plus a CIDR fallback removed from source and one duplicate. - template-generation's VPC cases use management: 'create-new'; with no VPC found, 'auto' is an explicit error since 37a354e. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
…leted serverless-template Both suites failed to load since the hexagonal refactor (7b36f0f) removed aws-discovery.js and serverless-template.js. - postgres-config.test.js is rewritten as a composer-level check of the current AuroraBuilder contract: off, external, managed (cluster, instance, snapshot policy, private subnet group, URL-safe secret, DATABASE_URL, IAM, 5432 ingress), custom settings, use-existing, discover found/not found, invalid mode, and skipping Aurora under frigg start. Discovery and the Prisma layer are stubbed. - integration.test.js is deleted: its subject (BuildTimeDiscovery env plumbing into a synchronous serverless-template with ${self:custom.vpc...} strings) no longer exists. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
… and reconciliation - Progress monitors: the .rejects matcher was attached after advancing fake timers, so Jest 30 reported an unhandled rejection; attach first. - Drift mocks used camelCase propertyPath; CloudFormation's PropertyDifference is PropertyPath: '/X'. - Follow intentional source changes: Lambda resource-mode reconciliation reports supportsResourceUpdate: true (6a0bba7); the orphan scan covers EC2, RDS and KMS (6c75188), so all three clients are mocked; import de-dup only warns about duplicates dropped for the same logical ID (6a0bba7). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
There was a problem hiding this comment.
If your organization's extra usage balance is empty, an organization admin can add extra usage credits at claude.ai/admin-settings/usage. If its monthly spend limit was reached, an admin can raise it on the same page. If neither applies, contact Anthropic support.
Once extra usage is available, someone with write access to this repository can comment @claude review on this pull request to trigger a review.
✅ Deploy Preview for friggframework-org canceled.
|
️✅ There are no secrets present in this pull request anymore.If these secrets were true positive and are still valid, we highly recommend you to revoke them. 🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request. |
| # can't take the --replSet argument, so start it directly. | ||
| - name: Start MongoDB replica set 🍃 | ||
| run: | | ||
| docker run -d --name mongo -p 27017:27017 mongo:8.0 --replSet rs0 --bind_ip_all |
| node-version: 22.x | ||
| cache: npm | ||
|
|
||
| - name: Install Dependencies 🛠 |
| node-version: 22.x | ||
| cache: npm | ||
|
|
||
| - name: Install Dependencies 🛠 |
The mongodb-memory-server lockfile update dropped node_modules/encoding
(an optional peer of node-fetch) along with md5-file. The npm bundled
with Node 24.21 rejects that lockfile in `npm ci` ("Missing:
encoding@0.1.14 from lock file"), although Node 22's npm accepts it.
Restore the two entries exactly as they are on next.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
The db job's Postgres uses trust auth, so the workflow carries no credential for secret scanners to flag. npx calls use --no-install so CI never fetches a package at run time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
seanspeaks
left a comment
There was a problem hiding this comment.
Verdict: no blockers. The CI changes and most of the test updates hold up. Fix the two encryption should-fixes before this ships in a release, because the registry fix turns encryption on for fields that have only ever held plaintext.
Reviewed at 9045bbc. Everything below was checked locally, either by running it or by reading the source. Anything I couldn't confirm is labelled.
Blocking
None.
Should-fix
1. Module encryption errors are still swallowed at debug level, so one bad entry leaves every module field unencrypted. packages/core/database/encryption/encryption-schema-registry.js:274, also :149
The root cause in 2a2adff was a require error hidden by logger.debug. That handler is unchanged, so the next failure will be just as quiet. Repro: a module declares encryption: { credentialFields: ['api_key', 42] }. Then field.startsWith throws TypeError: field.startsWith is not a function at :149. loadCustomEncryptionSchema catches it at debug level, and no module field from any module gets registered. The fields are written in plaintext and nothing reaches the logs at the default level. An invalid app encryption.schema has the same effect, because it throws before modules load. Suggested fix:
- log at
warnorerrorwhen an app definition was found but loading failed; - validate or skip each module's entries one at a time, so one bad module can't drop the rest.
2. Some plaintext values don't survive the newly registered module fields on the Prisma path. packages/core/database/encryption/field-encryption-service.js:149-155, :239-249
The commit says plaintext values still read back. That holds on the DocumentDB service, which needs exactly 4 base64 parts and more than 50 chars, but not on the Prisma FieldEncryptionService. I checked with an AES Cryptor and a module listing webhook_secret and pin:
-
Values with 3 or more colons are treated as ciphertext. Example:
'a:b:c:d', or any URL with userinfo and a port._isEncryptedonly checkssplit(':').length >= 4, which causes two problems:- on write,
_shouldEncryptskips the value, so it stays plaintext even though the field is registered; - on read,
cryptor.decryptthrowsEncryption key not found, andprisma-encryption-extension.jsdoesn't catch it, so loading the whole Credential fails.
Before this PR these module fields weren't registered, so such values read fine. After upgrading, they break existing credentials.
- on write,
-
Numeric strings come back as numbers.
'123456'is stored encrypted and reads back as123456, because_deserializeAfterDecryptionrunsJSON.parseon it. A module that calls string methods on the field will throw.
Both problems already exist for core fields; this PR exposes every module field to them. Suggested fix: share the DocumentDB _isEncryptedValue check, and make the read path keep the value's type, at least for primitives that were strings before encryption.
3. The concurrency group also cancels CI on pushes to next. .github/workflows/frigg-ci.js.yml:15-17
group: ${{ github.workflow }}-${{ github.ref }} with cancel-in-progress: true means two quick merges to next cancel the first commit's run. release.yml publishes a prerelease on every push to next with no CI gate, so that published version never gets a CI result. Suggested fix: cancel-in-progress: ${{ github.event_name == 'pull_request' }}.
4. Two VpcBuilder tests were flipped to match the source on a disputed backwards-compatibility point. packages/devtools/infrastructure/domains/networking/vpc-builder.test.js:839-843, :1606-1611
On next, both tests asserted that a stack already containing FriggSubnet{1,2}RouteAssociation keeps those logical IDs. The second test's comment says "We MUST use these same logical IDs to avoid AlreadyExists errors". The source at vpc-builder.js:1825-1829 always emits FriggPrivateSubnet{1,2}RouteTableAssociation. The PR rewrote both tests to bless the source behaviour. The tests and that source logic came from the same commit (37a354e), so the intent isn't clear from history.
The risk is an EC2 constraint I didn't deploy to confirm. A subnet can have only one explicit route-table association, and CloudFormation creates the new logical resource before deleting the old one. So on a stack whose old associations are intact, the update can fail with Resource.AlreadyAssociated and roll back. Rather than settle this in a CI-green PR, it.skip these two with an issue, or get the 37a354e author to confirm that new IDs are intended.
Nits
-
packages/test/mongodb.js:9: the pinned version means two MongoDB downloads. The pin is 8.0.17, butmongodb-memory-server11's postinstall downloads its own default, 8.2.6. Afternpm ci, 8.2.6 was innode_modules/.cache/mongodb-memory-server, andTestMongothen downloaded 8.0.17. The pinned version is never pre-fetched, and the default is fetched but never used. That happens:- on every CI
buildandlintrun, which aren't cached; - in every app, since
@friggframework/devtoolshas@friggframework/testas a runtime dependency.
Pin to the library default, or set
MONGOMS_VERSION/MONGOMS_DISABLE_POSTINSTALLwhere it matters. - on every CI
-
frigg-ci.js.yml:104-108: the replica-set wait can time out without failing the step. If the node never becomes primary, the loop ends with status 0 (the last command issleep 1), and the failure only appears later as a confusingprisma db pusherror. Add a check after the loop. The first loop is fine: ifmongoshnever answers,rs.initiatefails the step. -
frigg-ci.js.yml:56-58: the CLI smoke loop can't catch a removed command.npx frigg nonexistent-cmd --helpexits 0, because commander prints the top-level help. Also,frigg-cli/index.js:78-89requires every command module eagerly, sofrigg --helpalone already proves they load. To catch a dropped or renamed command, grep the--helpoutput for each name. -
The
buildjob has nopermissions:block. Now that git-auto-commit is gone, add a top-levelpermissions: contents: read. -
docs/TESTING.md:241-256is stale. It still says integration tests automatically get an in-memory MongoDB withMONGO_URI. That's no longer true for core; point to*.db.test.js,npm run test:dband opt-inTestMongo. -
cd616a5 calls the
batchSendissue a delivery-path bug, but it isn't one. The old in-placespliceran afterawait sqs.send(...)returned, so SDK middleware and retries saw the right entries; only later observers such as the mock recorder saw 5/5/5. The fix is correct; just don't list it as a production fix in release notes. -
65014bc says the NAT tests it removed are "covered" in vpc-builder tests, which is only partly true. Never reusing a NAT gateway placed in a private subnet is covered (
vpc-builder.test.js:850-896). Throwing whenselfHeal: falseis not: that guard no longer exists. The current code (vpc-builder.js:240,:1706) silently creates a new, billable NAT gateway. That changed in 7b36f0f, not here, but it deserves an issue.
Tests that no longer run, with verdicts
| What | Tests | Verdict |
|---|---|---|
devtools/infrastructure/scripts/build-time-discovery.test.js, describe.skip |
23 | OK. Its subject requires the deleted aws-discovery. Note that build-time-discovery.js and run-discovery.js still ship and would throw if run (#708). |
orphan-detection-relationship-analysis.test.js, describe.skip |
4 | OK. findOrphanedResourcesWithRelationships doesn't exist (#709). |
devtools/frigg-cli/index.test.js, deleted |
3 | OK. It asserted the pre-#639 install flow, which install.test.js now covers. |
devtools/infrastructure/integration.test.js, deleted |
9 | OK. Its subject, serverless-template and BuildTimeDiscovery plumbing, is gone. |
management-ui Vitest suites, excluded by devtools/jest.config.js |
4 files | OK as stated, but nothing runs them now. |
infrastructure-composer.test.js, 91 → 76 tests |
15 | Mostly OK. Discovery gating is in resource-discovery.test.js, NAT placement is in the vpc-builder tests, and the CIDR fallback is gone from the source. The exception is the selfHeal throw (nit above). |
postgres-config.test.js, 26 → 17 tests |
9 | OK. Deletion protection, CloudWatch log exports and the VPC/2-subnet errors are no longer in AuroraBuilder. |
find-integration-context…test.js: "entity user missing" removed |
1 | OK. The use case no longer looks up the user (a7bacab). |
webhook-flow.integration.test.js: default ON_WEBHOOK log assertion |
1 | OK. The base handler has been a no-op since b74f21e. |
Core *.db.test.js (3 encryption suites, 2 parity suites) and the TestMongo smoke test |
— | Moved to the db job, which does run them. I pointed the Postgres URL at a dead port and npm run test:db exited 1, so failures fail the job. There's no continue-on-error. |
I found no .only, no raised timeouts and no new passWithNoTests. The other updated assertions match the intended behaviour in source: Boom status codes, the DocumentDB envelope, { externalId, type }, 32-byte keys, Lambda supportsResourceUpdate, the drift PropertyPath shape, the default-SG reuse from 37a354e, and the KMS env-var fallback (kms-builder.js:222-233).
Checked and fine
- Encryption merge. Module fields merge with the app's custom schema, and calling the loader repeatedly gives the same result. A module that lists a core field like
api_keyis filtered out rather than failing validation. Modules can only add fields: the opt-out comes only from the app'sencryption.disable, and nothing reads opt-outs from module definitions. - VpcBuilder fixes. The
securityGroupIdsfix is correct and covered (infrastructure-composer.test.js:425-433). The managed-mode legacy fix is correct and covered: reverting 82ddf5c makesvpc-builder.test.jsfail. - Global Mongo removal. No code or unit test in the monorepo relies on
MONGO_URIorglobal.testMongofrom core's global setup;prisma.test.jssets its own.@friggframework/test's exports andglobalSetup/globalTeardownare unchanged. - Lockfile. There are no downgrades, and the changes stay within the
mongodb-memory-serversubtree. The hoistedmongodbmoves from 4.17.2 to 7.5.0, but nothing in the workspace requiresmongodb. - Workflows.
pull_request: branches: ["**"]covers stacked PRs.continue-on-erroron lint applies only to the step.test-cli.ymlwas path-filtered onpackages/frigg-cli/**, which no longer exists, so it only ever ran when the workflow file itself changed. Nothing is lost by deleting it.- No secrets are used and no
pull_request_targetwas added.
What I ran
npm cion Node 24.10.0 and 22.11.0: both pass. On 22.11 there are only engine warnings that already existed.npm run test:allon both Node versions: everything passes. Core has 198 suites (2620 passed, 2 skipped), devtools 90 + 3 skipped (1944 passed, 37 skipped), admin-scripts 278, schemas 129 and serverless-plugin 46.npm run test:dbon Node 24 againstmongo:8.0(replica set) andpostgres:16in Docker, with migrations anddb pushapplied as the workflow does: core passed 5 suites (1438 tests) and test passed 1 suite.- The CLI smoke loop.
- Small probes of the encryption registry and service, using a real AES
Cryptor.
🤖 Generated with Claude Code
seanspeaks
left a comment
There was a problem hiding this comment.
Verdict: no blockers. The CI changes and most of the test updates hold up. Fix the two encryption should-fixes before this ships in a release, because the registry fix turns encryption on for fields that have only ever held plaintext.
Reviewed at 9045bbc. Everything below was checked locally, either by running it or by reading the source. Anything I couldn't confirm is labelled.
Blocking
None.
Should-fix
1. Module encryption errors are still swallowed at debug level, so one bad entry leaves every module field unencrypted. packages/core/database/encryption/encryption-schema-registry.js:274, also :149
The root cause in 2a2adff was a require error hidden by logger.debug. That handler is unchanged, so the next failure will be just as quiet. Repro: a module declares encryption: { credentialFields: ['api_key', 42] }. Then field.startsWith throws TypeError: field.startsWith is not a function at :149. loadCustomEncryptionSchema catches it at debug level, and no module field from any module gets registered. The fields are written in plaintext and nothing reaches the logs at the default level. An invalid app encryption.schema has the same effect, because it throws before modules load. Suggested fix:
- log at
warnorerrorwhen an app definition was found but loading failed; - validate or skip each module's entries one at a time, so one bad module can't drop the rest.
2. Some plaintext values don't survive the newly registered module fields on the Prisma path. packages/core/database/encryption/field-encryption-service.js:149-155, :239-249
The commit says plaintext values still read back. That holds on the DocumentDB service, which needs exactly 4 base64 parts and more than 50 chars, but not on the Prisma FieldEncryptionService. I checked with an AES Cryptor and a module listing webhook_secret and pin:
-
Values with 3 or more colons are treated as ciphertext. Example:
'a:b:c:d', or any URL with userinfo and a port._isEncryptedonly checkssplit(':').length >= 4, which causes two problems:- on write,
_shouldEncryptskips the value, so it stays plaintext even though the field is registered; - on read,
cryptor.decryptthrowsEncryption key not found, andprisma-encryption-extension.jsdoesn't catch it, so loading the whole Credential fails.
Before this PR these module fields weren't registered, so such values read fine. After upgrading, they break existing credentials.
- on write,
-
Numeric strings come back as numbers.
'123456'is stored encrypted and reads back as123456, because_deserializeAfterDecryptionrunsJSON.parseon it. A module that calls string methods on the field will throw.
Both problems already exist for core fields; this PR exposes every module field to them. Suggested fix: share the DocumentDB _isEncryptedValue check, and make the read path keep the value's type, at least for primitives that were strings before encryption.
3. The concurrency group also cancels CI on pushes to next. .github/workflows/frigg-ci.js.yml:15-17
group: ${{ github.workflow }}-${{ github.ref }} with cancel-in-progress: true means two quick merges to next cancel the first commit's run. release.yml publishes a prerelease on every push to next with no CI gate, so that published version never gets a CI result. Suggested fix: cancel-in-progress: ${{ github.event_name == 'pull_request' }}.
4. Two VpcBuilder tests were flipped to match the source on a disputed backwards-compatibility point. packages/devtools/infrastructure/domains/networking/vpc-builder.test.js:839-843, :1606-1611
On next, both tests asserted that a stack already containing FriggSubnet{1,2}RouteAssociation keeps those logical IDs. The second test's comment says "We MUST use these same logical IDs to avoid AlreadyExists errors". The source at vpc-builder.js:1825-1829 always emits FriggPrivateSubnet{1,2}RouteTableAssociation. The PR rewrote both tests to bless the source behaviour. The tests and that source logic came from the same commit (37a354e), so the intent isn't clear from history.
The risk is an EC2 constraint I didn't deploy to confirm. A subnet can have only one explicit route-table association, and CloudFormation creates the new logical resource before deleting the old one. So on a stack whose old associations are intact, the update can fail with Resource.AlreadyAssociated and roll back. Rather than settle this in a CI-green PR, it.skip these two with an issue, or get the 37a354e author to confirm that new IDs are intended.
Nits
-
packages/test/mongodb.js:9: the pinned version means two MongoDB downloads. The pin is 8.0.17, butmongodb-memory-server11's postinstall downloads its own default, 8.2.6. Afternpm ci, 8.2.6 was innode_modules/.cache/mongodb-memory-server, andTestMongothen downloaded 8.0.17. The pinned version is never pre-fetched, and the default is fetched but never used. That happens:- on every CI
buildandlintrun, which aren't cached; - in every app, since
@friggframework/devtoolshas@friggframework/testas a runtime dependency.
Pin to the library default, or set
MONGOMS_VERSION/MONGOMS_DISABLE_POSTINSTALLwhere it matters. - on every CI
-
frigg-ci.js.yml:104-108: the replica-set wait can time out without failing the step. If the node never becomes primary, the loop ends with status 0 (the last command issleep 1), and the failure only appears later as a confusingprisma db pusherror. Add a check after the loop. The first loop is fine: ifmongoshnever answers,rs.initiatefails the step. -
frigg-ci.js.yml:56-58: the CLI smoke loop can't catch a removed command.npx frigg nonexistent-cmd --helpexits 0, because commander prints the top-level help. Also,frigg-cli/index.js:78-89requires every command module eagerly, sofrigg --helpalone already proves they load. To catch a dropped or renamed command, grep the--helpoutput for each name. -
The
buildjob has nopermissions:block. Now that git-auto-commit is gone, add a top-levelpermissions: contents: read. -
docs/TESTING.md:241-256is stale. It still says integration tests automatically get an in-memory MongoDB withMONGO_URI. That's no longer true for core; point to*.db.test.js,npm run test:dband opt-inTestMongo. -
cd616a5 calls the
batchSendissue a delivery-path bug, but it isn't one. The old in-placespliceran afterawait sqs.send(...)returned, so SDK middleware and retries saw the right entries; only later observers such as the mock recorder saw 5/5/5. The fix is correct; just don't list it as a production fix in release notes. -
65014bc says the NAT tests it removed are "covered" in vpc-builder tests, which is only partly true. Never reusing a NAT gateway placed in a private subnet is covered (
vpc-builder.test.js:850-896). Throwing whenselfHeal: falseis not: that guard no longer exists. The current code (vpc-builder.js:240,:1706) silently creates a new, billable NAT gateway. That changed in 7b36f0f, not here, but it deserves an issue.
Tests that no longer run, with verdicts
| What | Tests | Verdict |
|---|---|---|
devtools/infrastructure/scripts/build-time-discovery.test.js, describe.skip |
23 | OK. Its subject requires the deleted aws-discovery. Note that build-time-discovery.js and run-discovery.js still ship and would throw if run (#708). |
orphan-detection-relationship-analysis.test.js, describe.skip |
4 | OK. findOrphanedResourcesWithRelationships doesn't exist (#709). |
devtools/frigg-cli/index.test.js, deleted |
3 | OK. It asserted the pre-#639 install flow, which install.test.js now covers. |
devtools/infrastructure/integration.test.js, deleted |
9 | OK. Its subject, serverless-template and BuildTimeDiscovery plumbing, is gone. |
management-ui Vitest suites, excluded by devtools/jest.config.js |
4 files | OK as stated, but nothing runs them now. |
infrastructure-composer.test.js, 91 → 76 tests |
15 | Mostly OK. Discovery gating is in resource-discovery.test.js, NAT placement is in the vpc-builder tests, and the CIDR fallback is gone from the source. The exception is the selfHeal throw (nit above). |
postgres-config.test.js, 26 → 17 tests |
9 | OK. Deletion protection, CloudWatch log exports and the VPC/2-subnet errors are no longer in AuroraBuilder. |
find-integration-context…test.js: "entity user missing" removed |
1 | OK. The use case no longer looks up the user (a7bacab). |
webhook-flow.integration.test.js: default ON_WEBHOOK log assertion |
1 | OK. The base handler has been a no-op since b74f21e. |
Core *.db.test.js (3 encryption suites, 2 parity suites) and the TestMongo smoke test |
— | Moved to the db job, which does run them. I pointed the Postgres URL at a dead port and npm run test:db exited 1, so failures fail the job. There's no continue-on-error. |
I found no .only, no raised timeouts and no new passWithNoTests. The other updated assertions match the intended behaviour in source: Boom status codes, the DocumentDB envelope, { externalId, type }, 32-byte keys, Lambda supportsResourceUpdate, the drift PropertyPath shape, the default-SG reuse from 37a354e, and the KMS env-var fallback (kms-builder.js:222-233).
Checked and fine
- Encryption merge. Module fields merge with the app's custom schema, and calling the loader repeatedly gives the same result. A module that lists a core field like
api_keyis filtered out rather than failing validation. Modules can only add fields: the opt-out comes only from the app'sencryption.disable, and nothing reads opt-outs from module definitions. - VpcBuilder fixes. The
securityGroupIdsfix is correct and covered (infrastructure-composer.test.js:425-433). The managed-mode legacy fix is correct and covered: reverting 82ddf5c makesvpc-builder.test.jsfail. - Global Mongo removal. No code or unit test in the monorepo relies on
MONGO_URIorglobal.testMongofrom core's global setup;prisma.test.jssets its own.@friggframework/test's exports andglobalSetup/globalTeardownare unchanged. - Lockfile. There are no downgrades, and the changes stay within the
mongodb-memory-serversubtree. The hoistedmongodbmoves from 4.17.2 to 7.5.0, but nothing in the workspace requiresmongodb. - Workflows.
pull_request: branches: ["**"]covers stacked PRs.continue-on-erroron lint applies only to the step.test-cli.ymlwas path-filtered onpackages/frigg-cli/**, which no longer exists, so it only ever ran when the workflow file itself changed. Nothing is lost by deleting it.- No secrets are used and no
pull_request_targetwas added.
What I ran
npm cion Node 24.10.0 and 22.11.0: both pass. On 22.11 there are only engine warnings that already existed.npm run test:allon both Node versions: everything passes. Core has 198 suites (2620 passed, 2 skipped), devtools 90 + 3 skipped (1944 passed, 37 skipped), admin-scripts 278, schemas 129 and serverless-plugin 46.npm run test:dbon Node 24 againstmongo:8.0(replica set) andpostgres:16in Docker, with migrations anddb pushapplied as the workflow does: core passed 5 suites (1438 tests) and test passed 1 suite.- The CLI smoke loop.
- Small probes of the encryption registry and service, using a real AES
Cryptor.
🤖 Generated with Claude Code
…when deployed Review of #710: loadCustomEncryptionSchema wrapped everything in one catch that logged at debug level, the same handler that hid the broken require fixed in 2a2adff. One non-string entry in a module's `encryption.credentialFields` (`field.startsWith is not a function`) or an invalid app `encryption.schema` dropped every module field, and those credentials were written in plaintext with nothing in the logs. - credentialFields are validated entry by entry: an invalid entry is skipped with a warning naming the module; valid entries from the same and other modules are still registered. - Only "no backend / no app definition" stays at debug level. Once an app definition is found, an invalid encryption.schema, encryption.disable or module schema is a configuration error: in deployed stages it is logged at error level and thrown as EncryptionSchemaError; in dev/test/local it is a warning and loading continues. - prisma.js rethrows EncryptionSchemaError instead of "Continuing without encryption", so startup fails rather than silently writing plaintext. Other extension-initialisation failures are unchanged here (#663 covers them). New tests fail on the previous source (4 of 5). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
…a encryption path Review of #710: registering module credentialFields turns encryption on for fields that have only ever held plaintext, and the Prisma FieldEncryptionService mishandled two kinds of such values. - Colons: _isEncrypted treated any string with 3+ colons as ciphertext. Plaintext like 'a:b:c:d' or a URL with userinfo and a port was never encrypted on write, and on read cryptor.decrypt threw ("Encryption key not found"), failing the whole Credential load. Both paths now share ciphertext-format.isEncryptedEnvelope, the strict check the DocumentDB path already used (exactly 4 base64-alphabet parts, > 50 chars). Values that don't match are plaintext; a real envelope that fails to decrypt still throws, so key errors aren't hidden. - Types: primitives were encrypted as String(value) and read back through JSON.parse, so '123456' came back as the number 123456. Every value is now JSON-encoded before encryption ('123456' -> "\"123456\""), so strings stay strings and numbers stay numbers. Ciphertext written by earlier versions still reads: raw strings that aren't JSON come back unchanged (a legacy raw string that is valid JSON, e.g. '123456', parses as it always did). Older readers also handle the new form, since JSON.parse('"x"') is 'x'. The new extension test (real AES Cryptor) fails on the previous source (3 of 5). The service and extension unit tests' mock cryptors now emit the real envelope shape. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
Review of #710: with cancel-in-progress on every ref, two quick merges to next cancelled the first commit's run, and release.yml publishes a prerelease for every push to next, so that version never got a CI result. Superseded PR runs are still cancelled; pushes to main/next are not. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
…ending #714 Review of #710: two VpcBuilder tests had been flipped to accept that a stack with FriggSubnet{1,2}RouteAssociation gets FriggPrivateSubnet{1,2}RouteTableAssociation instead. History doesn't settle it. 37a354e changed the source to always emit the new IDs, with a comment saying this is deliberate (force CloudFormation to recreate drifted associations), and in the same commit kept tests that expect the old IDs "to avoid AlreadyExists errors". A subnet takes only one explicit route-table association and CloudFormation creates the new logical resource before deleting the old one, so on a stack whose old associations are intact the rename could fail with Resource.AlreadyAssociated and roll back. Choosing between that and the drift fix is a product call, so the source is left alone and: - "should add UpdateReplacePolicy…" is back to its original old-ID assertions and it.skip'ped, pointing at #714; - the backwards-compatibility test keeps running for the NAT route and VPC endpoint IDs but no longer asserts the association IDs either way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
…MongoDB at install Review of #710: mongodb-memory-server's postinstall downloads the library's default binary (8.2.6) on every `npm ci`, while TestMongo pins and downloads 8.0.17 at first use, so every install fetched a ~100 MB binary that nothing used. Because @friggframework/devtools depends on @friggframework/test at runtime, that happened in every Frigg app too, and MONGOMS_DISABLE_POSTINSTALL or package.json config in this repo can't reach an app's install (the hook reads INIT_CWD's package.json). @friggframework/test now depends on mongodb-memory-server-core, the same library without the install hook; TestMongo only ever fetches the pinned version. The lockfile change is just the dropped wrapper package (and its tslib) plus the renamed dependency. install-footprint.test.js fails on the previous dependency. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
Review of #710: `frigg <unknown> --help` exits 0 (commander prints the top-level help), so the per-command --help loop could never fail for a missing command. `frigg --help` already loads every command module; the step now also checks that each expected command is listed in it. Checked locally: the list passes, and adding a nonexistent command fails the step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
Review of #710: the wait loop ended with `sleep 1`, so a node that never became primary left the step green and the failure surfaced later as a confusing `prisma db push` error. The step now fails with an error and the container log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
Review of #710: the build job had no permissions block. With the lint auto-commit gone no job needs write access, so contents: read is set at workflow level (db and lint already declared it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
Review of #710: the MongoDB section still said integration tests get an in-memory MongoDB with MONGO_URI from the test setup, which core no longer provides. It now explains the *.db.test.js convention, npm run test:db, the FRIGG_TEST_* URLs, how CI and a local run provide the databases, and TestMongo as an opt-in helper for apps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
|
Thanks for the review. Every should-fix and nit is addressed in the commits listed below. Each code fix comes with a test that fails on the previous source. CI is green at 7cfcf12: https://github.com/friggframework/frigg/actions/runs/40062491876 1. Encryption-registry errors swallowed at debug level (325d9af)
2. Plaintext and typed values on the Prisma path (3993629)
3. Concurrency on
4. Route-association tests (3c342b4)
Nits
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 7cfcf12. Configure here.
| function isLocalStage() { | ||
| const stage = process.env.STAGE || process.env.NODE_ENV || 'development'; | ||
| return ['dev', 'test', 'local'].includes(stage.toLowerCase()); | ||
| } |
There was a problem hiding this comment.
Local stage check misses development
Medium Severity
isLocalStage treats development as deployed even though that is both its own fallback and the usual NODE_ENV for local Node. An invalid encryption.schema now throws and blocks startup, contrary to the lenient local-stage path. It is also case-insensitive, while Prisma’s encryption bypass is not, so STAGE=DEV can encrypt with a warned-away schema.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 7cfcf12. Configure here.
| @@ -1,4 +1,5 @@ | |||
| const { Cryptor } = require('../encrypt/Cryptor'); | |||
| const { isEncryptedEnvelope } = require('./encryption/ciphertext-format'); | |||
There was a problem hiding this comment.
DocumentDB validates schema when encryption is off
Medium Severity
DocumentDBEncryptionService now runs loadCustomEncryptionSchema before it decides encryption is off. That load can throw EncryptionSchemaError, so constructing the repository fails even when the stage would bypass encryption or no KMS/AES keys are set. Prisma only loads the schema after encryption is enabled, so the same config still starts on Mongo/Postgres.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 7cfcf12. Configure here.
|
🚀 PR was released in |
|






Summary
Gets Frigg CI green on
next(runbook G0). Onnext, CI had failed on every recent run. Core's suite never ran, and devtools had about 30 failing suites. The tests had gone stale while CI stayed red, and a few real bugs were hiding underneath.Mongo root cause and fix
mongodb-memory-server8.x defaults to MongoDB 5.0.19. Its only Linux builds target Ubuntu 20.04 and link OpenSSL 1.1.ubuntu-latestis now 24.04, which has nolibcrypto.so.1.1. Core's jestglobalSetupstarted that server before every run, so a failed start (StdoutInstanceError) meant none of core's ~200 suites ran.STAGE=devdefault. Unit suites must not need a database.@friggframework/testnow usesmongodb-memory-server11.TestMongopins MongoDB 8.0.17, which has native ubuntu2404 builds;MONGOMS_VERSIONstill overrides it.TestMongostays as an opt-in helper.peer-flag churn was left out.Real-database tests split out (
*.db.test.js,npm run test:db)*.db.test.js.test:allexcludes them, and a new paralleldbjob runs them:TestMongosmoke test.dbjob provides MongoDB 8.0 as a replica set (Prisma needs one for MongoDB) and a postgres:16 service, with migrations applied and the mongodb-memory-server binary cached.nextyet. The Postgres service in thedbjob is what it will use when it lands (runbook DG3); it only needsFRIGG_TEST_POSTGRES_URL, which the job already sets.Bugs found by the revived tests
fix(core): API-moduleencryption.credentialFieldswere never registered. A wrong relativerequirepath threw, and the error was swallowed at debug level, so those credential fields were stored unencrypted. Fixing the path exposed two more problems, both fixed:api_key) failed validation and dropped every module's fields;Values already stored as plaintext still read back.
fix(core):QueuerUtil.batchSendreused and cleared one array across every SQS batch command.fix(devtools): VpcBuilder attached only the first ofvpc.securityGroupIds.fix(devtools): VpcBuilder applied legacy VPC options undermanagementMode: 'managed'even though it warns that it ignores them. Managed + isolated with no stack VPC then failed.Stale tests updated
Each commit names the change that made the test stale. In short:
{ externalId, type }API, Boom status codes, 32-byte keys, AWS SDK v3 SQS mock, deterministic timing, and Node 22 warnings in the require-graph probe.npm installintolayers/prisma, and template-generation no longer runs real AWS discovery;Skips (both
describe.skipwith a comment and an issue)devtools/infrastructure/scripts/build-time-discovery.test.jsaws-discoverymodule and nothing calls it; decide whether to delete or port itdevtools/.../orphan-detection-relationship-analysis.test.jsAlso not in this PR:
devtools/frigg-cli/index.test.jsanddevtools/infrastructure/integration.test.js.management-ui's Vitest suites are excluded from devtools' jest. management-ui isn't an npm workspace, so its dependencies are never installed; running them in CI is a follow-up.it.skipin core's requester tests, plus one skipped suite and others in devtools.Workflow changes (one commit each, so any can be dropped)
on.pushincludesnext.fail-fast: false.setup-nodenpm cache, no global npm reinstall, and newer pushes cancel in-flight runs.lint:fixplus git-auto-commit is replaced by a read-only lint job (prettier --check+eslint). It is non-blocking (continue-on-error) because the backlog is large: core alone has about 390 files that need prettier and 96 eslint errors. No bot pushes to PR branches any more.test-cli.ymlis retired. It failed on every run: wrong path (packages/frigg-climoved) and Node 18/20/21. Its unit tests already run intest:all. Thefrigg <cmd> --helpchecks are now a step in Frigg CI. The Windows/macOS legs and the Codecov gate are dropped.codesee-arch-diagram.ymlis left as is. CodeSee's action repo turned the action into a no-op and then reverted that; runs still succeed and codesee.io still responds. I couldn't confirm the service is defunct, so that's the maintainer's call.release.ymlandcodeql.ymlare untouched.Review follow-ups
next.@friggframework/testnow usesmongodb-memory-server-core, so nothing downloads a binary at install time.TESTING.mdnits.QueuerUtil.batchSend(cd616a5): this fix only affects what tests and other observers see. The SQS requests were already correct, so it isn't a production fix.vpc.selfHeal: falseno longer throws when an existing NAT gateway is misplaced. Since 7b36f0f, VpcBuilder silently creates a new, billable NAT gateway instead (vpc-builder.js~240, ~1706). The removed composer tests covered that guard; the vpc-builder tests cover NAT placement but not this.Test plan
npm run test:allpasses locally on Node 22 and 24.npm run test:dbpasses against mongo:8.0 (replica set) and postgres:16.🤖 Generated with Claude Code
https://claude.ai/code/session_013b2UUFaQ5Lk6TFPqzRr1j7
Note
High Risk
Changes touch credential encryption registration, envelope handling, and production startup on invalid encryption config—areas where mistakes could leave secrets plaintext or block deploys; CI workflow changes also gate every
nextpublish.Overview
Restructures Frigg CI so
nextcan go green: pushes onnext, Node 22/24 matrix, PR concurrency cancellation, read-only tokens, a dedicateddbjob (Mongo replica set + Postgres,npm run test:db), read-only lint (non-blocking), and afrigg --helpcommand-list smoke test;test-cli.ymlis removed. Docs describe*.db.test.jsand local DB setup.Core test infrastructure no longer starts in-memory Mongo in global setup (fixes Ubuntu 24 / mongodb-memory-server breakage); real DB suites move to
*.db.test.js/jest.db.config.js. Lockfile bumps mongodb-memory-server (and driver stack).Field-level encryption gets stricter Cryptor envelope detection (legacy plaintext with colons no longer treated as ciphertext), JSON type-preserving encrypt/decrypt, shared
isEncryptedEnvelope, and startup fails closed on invalid app encryption config in deployed stages. Moduleencryption.credentialFieldsregistration is fixed (correct require path, per-field validation, merge with app custom schema, skip core duplicates)—fields that were silently unencrypted should encrypt on new writes; plaintext legacy values still read.findIntegrationContextByExternalEntityIdnow takes{ externalId, type }(docs/tests updated).QueuerUtil.batchSendcopies each SQS batch instead of clearing a sharedEntriesarray. Many stale unit/integration tests are updated (AWS SDK v3 SQS, Boom assertions, timing mocks, etc.).Reviewed by Cursor Bugbot for commit 7cfcf12. Bugbot is set up for automated code reviews on this repo. Configure here.
📦 Published PR as canary version:
2.0.0--canary.710.7cfcf12.0✨ Test out this PR locally via:
npm install @friggframework/admin-scripts@2.0.0--canary.710.7cfcf12.0 npm install @friggframework/core@2.0.0--canary.710.7cfcf12.0 npm install @friggframework/devtools@2.0.0--canary.710.7cfcf12.0 npm install @friggframework/eslint-config@2.0.0--canary.710.7cfcf12.0 npm install @friggframework/prettier-config@2.0.0--canary.710.7cfcf12.0 npm install @friggframework/schemas@2.0.0--canary.710.7cfcf12.0 npm install @friggframework/serverless-plugin@2.0.0--canary.710.7cfcf12.0 npm install @friggframework/test@2.0.0--canary.710.7cfcf12.0 npm install @friggframework/ui@2.0.0--canary.710.7cfcf12.0 # or yarn add @friggframework/admin-scripts@2.0.0--canary.710.7cfcf12.0 yarn add @friggframework/core@2.0.0--canary.710.7cfcf12.0 yarn add @friggframework/devtools@2.0.0--canary.710.7cfcf12.0 yarn add @friggframework/eslint-config@2.0.0--canary.710.7cfcf12.0 yarn add @friggframework/prettier-config@2.0.0--canary.710.7cfcf12.0 yarn add @friggframework/schemas@2.0.0--canary.710.7cfcf12.0 yarn add @friggframework/serverless-plugin@2.0.0--canary.710.7cfcf12.0 yarn add @friggframework/test@2.0.0--canary.710.7cfcf12.0 yarn add @friggframework/ui@2.0.0--canary.710.7cfcf12.0