Skip to content

Conversation

@elliotBraem
Copy link
Collaborator

@elliotBraem elliotBraem commented Jun 11, 2025

  • auto retweeting

Summary by CodeRabbit

  • New Features
    • Introduced a dedicated secret management service with encrypted storage, retrieval, and signing capabilities for sensitive data.
    • Added API endpoints for securely storing, retrieving, and signing secrets, with authentication and detailed error handling.
    • Integrated a client for secure secret retrieval and usage within the main application, enabling dynamic secret hydration for plugins.
  • Improvements
    • Enhanced plugin and processing workflows to support feed-specific secret management and context-aware transformations.
  • Documentation
    • Added setup instructions and configuration details for the new secret management service.
  • Chores
    • Added configuration files for TypeScript, Docker, and Git to support the new service and database schema.
  • Bug Fixes
    • Improved validation and error messaging for required environment variables and secret handling.

itexpert120 and others added 30 commits March 24, 2025 21:25
* Get basic working

* adds rss feeds

* added stablewatch founder and stablecoin intern from messaria as approvers on stablecoins feed

* fixes to config for grants, sui, and telegram channels (#102)

* add query param for selective processing (#103)

* adds query param to process

* add query param for processing

* simplify

* add tags

* Feat: implement frontend leaderboard (#93)

* feat: implement frontend leaderboard

* feat: implement a leaderboard in frontend

* feat: implemented leaderboard

* fix: rebuild implement leaderboard

* fix: prettier

* fix: prettier

* fix: reimplement frontend leaderboard

* fix: implement frontend leaderboard

* approval rate

* sets approval rate and hides curator

---------

Co-authored-by: Elliot Braem <elliot@ejlbraem.com>

* remove tailwind-scrollbar

* added bob to desci feed

* Get basic working

* set .env.example

* nitpicks

---------

Co-authored-by: Elliot Braem <elliot@ejlbraem.com>
Co-authored-by: codingshot <45281667+codingshot@users.noreply.github.com>
Co-authored-by: Elliot Braem <elliot@everything.dev>
Co-authored-by: Louis <112561517+louisdevzz@users.noreply.github.com>
* Explore Page - commit-1

* Explore Page - commit-2

* explore page - commit-3

* explore page - commit - 4

* explore page - commit - prettier

* explore page responsiveness + code Rabbit Comments

* code Rabbit Comments resolved

* css updates

* css changes 2

* header update + mobile responsive

* conflicts resolved

* Rebase and changes

* Fix fmt
* Explore Page - commit-1

* Explore Page - commit-2

* explore page - commit-3

* explore page - commit - 4

* explore page - commit - prettier

* explore page responsiveness + code Rabbit Comments

* code Rabbit Comments resolved

* css updates

* css changes 2

* header update + mobile responsive

* conflicts resolved

* Rebase and changes

* Fix fmt

* Header Updates + Web3Auth getUserInfo + Explore Page changes

* fmt

* coderabbit comments resolved
* Update the FE to have the profile page (header and tabs init)

* Move tabs to it's own component

* Add stats and top badges to overview

* Finish the overview tab

* Update overview page and init content page

* feat(profile-page): add Content and My Feed tags

* feat(profile-page): finish profile page static UI

* refactor: fmt
* Curate Engine Step 1

* content-progress-configuration step-1

* Curation Settings Part 2 and 3

* CodeRabbit Comments Resolved + Mobile Responsive

* Responsiveness: empty State, JSON check

---------

Co-authored-by: Elliot Braem <elliot@everything.dev>
* Submissions Page + Feed Page + Mobile Responsiveness

* fixes

* craete-feed authenticated user condition

* fmt

* remove sqlite

---------

Co-authored-by: Elliot Braem <elliot@ejlbraem.com>
* feat: Add connect button to feed page

* fix: recommit

* added back to stablecoins feed since stablewatch forked their own

* fix packages, update pg, and ignore cloudflare sockets

* fmt

---------

Co-authored-by: ethnclark <ethanclark1310@gmail.com>
Co-authored-by: codingshot <45281667+codingshot@users.noreply.github.com>
Co-authored-by: Elliot Braem <elliot@ejlbraem.com>
* fix: Sort By Oldest

* fix: Sort By Oldest

* fix: Fix RecentSubmissions Sort Order Update

* fix: All feed should be hidden, remove double title

---------

Co-authored-by: vohuunhan1310@gmail.com <ethanclark1310@gmail.com>
* UI fixes

* fmt

---------

Co-authored-by: Elliot Braem <elliot@everything.dev>
* fix: Leaderboard improvements

* fix: fmt

* reorganize

* remove unused

* rename

* clean up

* fmt

---------

Co-authored-by: Elliot Braem <elliot@ejlbraem.com>
@vercel
Copy link

vercel bot commented Jun 11, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
curatedotfun-app ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 11, 2025 3:09am

@coderabbitai
Copy link

coderabbitai bot commented Jun 11, 2025

Walkthrough

A new secret management service ("secret-service") is introduced, including its Docker, database schema, API, encryption, and service logic. The main application is updated to support secret hydration in plugins, propagating feedId through processing flows. Shared database schema and validators are extended for secrets. TypeScript configurations and project references are updated accordingly.

Changes

File(s) Change Summary
apps/api/src/env.ts Added required environment variables for secret service URL and API key.
apps/api/src/services/distribution.service.ts
apps/api/src/services/processor.service.ts
apps/api/src/services/transformation.service.ts
Added feedId parameter to method signatures and propagated through processing and transformation pipelines.
apps/api/src/services/plugin.service.ts Integrated secret hydration into plugin config using new secret service client; updated method signatures.
apps/api/src/services/secret-service-client.ts Added new API client for secret service with methods for retrieving secrets and signing payloads.
apps/api/src/services/feed.service.ts Updated to pass feedId to processor and removed redundant comments.
apps/api/src/utils/service-provider.ts Registered and exposed the new secret service client in the service provider.
apps/secret-service/.dockerignore
apps/secret-service/.gitignore
apps/secret-service/Dockerfile
apps/secret-service/README.md
apps/secret-service/package.json
apps/secret-service/tsconfig.json
Added new secret service app with Docker, ignore files, manifest, and TypeScript config.
apps/secret-service/src/index.ts Implemented secret service HTTP API with endpoints for getting, setting, and signing secrets.
apps/secret-service/src/db/index.ts Added DB initialization for secret service using shared schema and Drizzle ORM.
apps/secret-service/src/services/encryption.service.ts Added AES-256-GCM encryption/decryption service.
apps/secret-service/src/services/secret-store.service.ts Added service for storing and retrieving encrypted secrets from the database.
apps/secret-service/src/utils/crypto-helpers.ts Added utilities for buffer/hex conversions.
apps/secret-service/src/utils/logger.ts Added timestamped logging utility.
packages/shared-db/src/schema/index.ts Re-exported new secrets table schema.
packages/shared-db/src/schema/secrets.ts Added Drizzle ORM schema for secrets table with encrypted fields.
packages/shared-db/src/validators.ts Added Zod schemas and types for secrets table operations.
packages/shared-db/tsconfig.json
packages/utils/tsconfig.json
tsconfig.json
Updated TypeScript configs and project references for new secret service and schema changes.

Sequence Diagram(s)

sequenceDiagram
    participant API_Server
    participant SecretServiceApiClient
    participant SecretService
    participant Database

    API_Server->>SecretServiceApiClient: getPlaintextSecret(feedId, keyName)
    SecretServiceApiClient->>SecretService: POST /v1/secrets/get-plaintext
    SecretService->>Database: SELECT secret WHERE feedId, keyName
    Database-->>SecretService: Encrypted secret row
    SecretService->>SecretService: Decrypt secret
    SecretService-->>SecretServiceApiClient: Plaintext secret
    SecretServiceApiClient-->>API_Server: Plaintext secret
    API_Server->>Plugin: Hydrate config with secret
Loading
sequenceDiagram
    participant PluginService
    participant SecretServiceApiClient

    PluginService->>SecretServiceApiClient: getPlaintextSecret(feedId, VAR_NAME)
    SecretServiceApiClient-->>PluginService: Secret Value
    PluginService->>Plugin: Initialize with hydrated config
Loading

Poem

A secret hops from burrow deep,
Through keys and feeds, its promise to keep.
With bytes encrypted, safely stored,
The rabbit guards each precious hoard.
Now plugins thrive with secrets new,
And every feed is trusted too!
🐇🔐✨
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@elliotBraem
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Jun 11, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🔭 Outside diff range comments (1)
apps/api/src/services/plugin.service.ts (1)

1-1: ⚠️ Potential issue

Fix code formatting issues.

The pipeline indicates formatting issues in this file.

Run the following command to fix formatting:

pnpm prettier --write apps/api/src/services/plugin.service.ts
🧰 Tools
🪛 GitHub Actions: CI

[warning] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

🧹 Nitpick comments (17)
apps/secret-service/.gitignore (1)

1-29: Comprehensive ignore patterns—consider build artifacts.
The file correctly ignores editor, dependency, env, and log files. To prevent accidental commits of compiled outputs, add dist/ and TypeScript incremental build files (*.tsbuildinfo).

apps/secret-service/README.md (1)

1-11: Enrich README with setup and env details.
Consider documenting prerequisites (Node/PNPM versions), required environment variables (e.g., SECRET_SERVICE_INTERNAL_API_KEY), and example API endpoints. This will streamline onboarding and usage.

apps/api/src/services/feed.service.ts (1)

71-75: Redundant round-trip to DB for feedConfig

You already fetched the feed record one call earlier. If the Feed entity embeds its config, doing a second query (getFeedConfig) inside the same request adds latency and extra I/O.
Consider:

-const feedConfig = await this.feedRepository.getFeedConfig(feedId);
+const feedConfig = feed.config ?? await this.feedRepository.getFeedConfig(feedId);

If the repository intentionally separates the two, add a quick comment explaining why so future readers don’t assume this is an oversight.

apps/api/src/services/transformation.service.ts (1)

50-65: Uncaught plugin hydration failures bubble as generic errors

pluginService.getPlugin may now throw for missing secrets.
Consider wrapping it to attach stage / transformIndex context similar to the later error handling, so operators can immediately see which transform failed to hydrate.

-const plugin = await this.pluginService.getPlugin(
+const plugin = await this.pluginService.getPlugin(
     …
 ) // wrap in try/catch and convert to PluginError
apps/api/src/env.ts (1)

28-33: Mismatch between “required” typing and runtime fallback handling
SECRET_SERVICE_URL and SECRET_SERVICE_INTERNAL_API_KEY are declared mandatory here, yet ServiceProvider still contains a fallback logger.error branch and proceeds with ! non-null assertions. Either keep them mandatory (preferred) and drop the fallback logic, or mark them .optional() and handle absence robustly.

apps/secret-service/src/utils/crypto-helpers.ts (1)

15-17: Add minimal hex input validation
Buffer.from(hexString, "hex") silently ignores odd-length or non-hex characters, which can lead to silent corruption. Consider validating the input first:

-export function hexToBuffer(hexString: string): Buffer {
-  return Buffer.from(hexString, "hex");
+const HEX_RE = /^[0-9a-fA-F]+$/;
+export function hexToBuffer(hexString: string): Buffer {
+  if (hexString.length % 2 !== 0 || !HEX_RE.test(hexString)) {
+    throw new Error("Invalid hex string");
+  }
+  return Buffer.from(hexString, "hex");
 }
apps/secret-service/package.json (1)

1-31: Minor QoL scripts
A prepare script ("prepare": "npm run build") would let npm link / local installs compile automatically, and lint could be included in CI. Optional but useful.

apps/secret-service/src/utils/logger.ts (2)

1-6: Loosen log method typings to accept any value

Restricting the first argument to string forces callers to stringify objects up-front and loses rich console inspection. Accept unknown (or any) to mirror console.* signatures.

-export interface Logger {
-  info: (message: string, ...args: any[]) => void;
-  warn: (message: string, ...args: any[]) => void;
-  error: (message: string, ...args: any[]) => void;
-  debug: (message: string, ...args: any[]) => void;
+export interface Logger {
+  info: (message: unknown, ...args: unknown[]) => void;
+  warn: (message: unknown, ...args: unknown[]) => void;
+  error: (message: unknown, ...args: unknown[]) => void;
+  debug: (message: unknown, ...args: unknown[]) => void;
 }

18-25: debug still fires in production when DEBUG=true

The current guard prints debug logs in prod if someone sets DEBUG=true, which may leak sensitive data from the secret-service. Consider also checking NODE_ENV !== "production".

-    if (
-      process.env.NODE_ENV === "development" ||
-      process.env.DEBUG === "true"
-    ) {
+    if (
+      (process.env.NODE_ENV ?? "production") !== "production" &&
+      process.env.DEBUG === "true"
+    ) {
apps/api/src/services/processor.service.ts (1)

12-13: Inconsistent import extensions may break TS ↔ JS path mapping

This file imports

import { TransformationService } from "./transformation.service.js";

but other sibling imports omit extensions. Under moduleResolution: "NodeNext" this will compile, yet the .js suffix will be emitted into JS and may diverge from internal paths that still use bare specifiers. Align on one style (prefer suffix‐less within TS), or update all internal imports to .js.

-import { TransformationService } from "./transformation.service.js";
+import { TransformationService } from "./transformation.service";
apps/secret-service/src/services/encryption.service.ts (2)

60-66: Optimize encryption by working directly with Buffers.

The current implementation converts to hex strings during encryption and then back to Buffer, which is inefficient.

Apply this diff to work directly with Buffers:

-    let encrypted = cipher.update(plaintext, "utf8", "hex");
-    encrypted += cipher.final("hex");
+    const encrypted = Buffer.concat([
+      cipher.update(plaintext, "utf8"),
+      cipher.final()
+    ]);

     const authTag = cipher.getAuthTag();

     return {
-      encryptedValue: Buffer.from(encrypted, "hex"),
+      encryptedValue: encrypted,
       iv: iv,
       authTag: authTag,
     };

83-88: Optimize decryption by working directly with Buffers.

Similar to the encrypt method, avoid unnecessary hex string conversions.

Apply this diff to work directly with Buffers:

-      let decrypted = decipher.update(
-        encryptedValue.toString("hex"),
-        "hex",
-        "utf8",
-      ); // Provide 'hex' as inputEncoding for encryptedValue
-      decrypted += decipher.final("utf8");
+      let decrypted = decipher.update(encryptedValue, null, "utf8");
+      decrypted += decipher.final("utf8");
apps/api/src/services/secret-service-client.ts (1)

23-77: Consider RESTful conventions for API design.

While using POST for all operations provides consistency and avoids logging sensitive data in URLs, it deviates from RESTful conventions where GET is typically used for retrieval operations.

Consider:

  1. If security is the primary concern (avoiding sensitive data in URLs), document this design decision
  2. If following REST conventions, use GET for retrieval with proper authentication headers
  3. The empty object return on line 64 might be unexpected - consider returning null or undefined for truly empty responses
apps/secret-service/src/index.ts (1)

1-249: Consider adding rate limiting and request validation for production readiness.

The service has good security foundations with API key authentication and structured logging. For production deployment, consider adding:

  1. Rate limiting middleware to prevent abuse
  2. Request body size limits
  3. Input validation middleware (e.g., using Zod schemas)
  4. Structured error responses with correlation IDs
  5. Metrics/monitoring endpoints
apps/secret-service/Dockerfile (3)

1-8: Consider leveraging Corepack for pnpm instead of global installs

You currently install pnpm and turbo globally via npm install -g, which adds extra layers. You can use Corepack to manage pnpm without a global install:

RUN corepack enable \
 && corepack prepare pnpm@latest --activate

This reduces image size and simplifies your toolchain setup.


26-54: Consolidate COPY directives in builder stage

Multiple COPY steps (manifests then full source) create extra layers. You can merge related COPY instructions or refine .dockerignore to exclude unnecessary files—this will speed up cache hits and reduce image size.

🧰 Tools
🪛 Hadolint (2.12.0)

[error] 42-42: COPY with more than 2 arguments requires the last argument to end with /

(DL3021)


84-85: Copy only built artifacts to reduce runtime image bloat

Instead of copying the entire apps/secret-service directory, limit to the build output and essential files:

-COPY --from=builder --chown=app:app /app/apps/secret-service ./apps/secret-service
+COPY --from=builder --chown=app:app /app/apps/secret-service/dist ./apps/secret-service/dist
+COPY --from=builder --chown=app:app /app/apps/secret-service/package.json ./apps/secret-service/package.json

This avoids shipping source files and speeds up deployments.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 79f280d and afe8e25.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (26)
  • apps/api/src/env.ts (1 hunks)
  • apps/api/src/services/distribution.service.ts (3 hunks)
  • apps/api/src/services/feed.service.ts (2 hunks)
  • apps/api/src/services/plugin.service.ts (7 hunks)
  • apps/api/src/services/processor.service.ts (10 hunks)
  • apps/api/src/services/secret-service-client.ts (1 hunks)
  • apps/api/src/services/transformation.service.ts (2 hunks)
  • apps/api/src/utils/service-provider.ts (4 hunks)
  • apps/secret-service/.dockerignore (1 hunks)
  • apps/secret-service/.gitignore (1 hunks)
  • apps/secret-service/Dockerfile (1 hunks)
  • apps/secret-service/README.md (1 hunks)
  • apps/secret-service/package.json (1 hunks)
  • apps/secret-service/src/db/index.ts (1 hunks)
  • apps/secret-service/src/index.ts (1 hunks)
  • apps/secret-service/src/services/encryption.service.ts (1 hunks)
  • apps/secret-service/src/services/secret-store.service.ts (1 hunks)
  • apps/secret-service/src/utils/crypto-helpers.ts (1 hunks)
  • apps/secret-service/src/utils/logger.ts (1 hunks)
  • apps/secret-service/tsconfig.json (1 hunks)
  • packages/shared-db/src/schema/index.ts (1 hunks)
  • packages/shared-db/src/schema/secrets.ts (1 hunks)
  • packages/shared-db/src/validators.ts (2 hunks)
  • packages/shared-db/tsconfig.json (1 hunks)
  • packages/utils/tsconfig.json (1 hunks)
  • tsconfig.json (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (7)
apps/secret-service/src/db/index.ts (1)
packages/shared-db/src/validators.ts (1)
  • DB (10-10)
packages/shared-db/src/schema/secrets.ts (1)
packages/shared-db/src/schema/common.ts (1)
  • timestamps (14-22)
apps/secret-service/src/utils/logger.ts (1)
apps/api/src/services/processor.service.ts (1)
  • process (34-131)
packages/shared-db/src/validators.ts (1)
packages/shared-db/src/schema/secrets.ts (1)
  • secrets (37-54)
apps/secret-service/src/services/encryption.service.ts (1)
apps/secret-service/src/utils/logger.ts (1)
  • logger (8-26)
apps/api/src/services/secret-service-client.ts (1)
apps/secret-service/src/utils/logger.ts (2)
  • Logger (1-6)
  • logger (8-26)
apps/api/src/services/processor.service.ts (1)
packages/shared-db/src/validators.ts (1)
  • RichSubmission (122-125)
🪛 GitHub Actions: CI
apps/api/src/utils/service-provider.ts

[warning] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

packages/shared-db/src/schema/secrets.ts

[warning] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

packages/shared-db/src/validators.ts

[warning] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

apps/secret-service/src/services/secret-store.service.ts

[warning] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

apps/api/src/services/plugin.service.ts

[warning] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

🪛 Hadolint (2.12.0)
apps/secret-service/Dockerfile

[error] 42-42: COPY with more than 2 arguments requires the last argument to end with /

(DL3021)

🔇 Additional comments (17)
packages/utils/tsconfig.json (2)

3-4: Reordered compilerOptions for clarity.
Moving "rootDir" and "outDir" to the top aligns with other packages and highlights input/output paths.


3-4: Confirm removal of explicit target.
By omitting "target", this package inherits the monorepo default (es2022). Verify that all downstream consumers support this target.

tsconfig.json (1)

4-6: Include secret-service in the project references.
Adding { "path": "./apps/secret-service" } integrates the new service into the monorepo build. Verify that apps/secret-service/tsconfig.json exists and is configured correctly for incremental builds.

packages/shared-db/src/schema/index.ts (1)

9-9: Expose the new secrets schema.
Exporting ./secrets makes the secrets table available via the shared schema index. Ensure src/schema/secrets.ts and its corresponding validators in validators.ts are implemented and tested.

apps/api/src/services/feed.service.ts (1)

157-158: 💡 Verification agent

🧩 Analysis chain

Signature drift check

processorService.process now accepts feedId. Make sure all call-sites (cron jobs, tests, CLI scripts) were updated; otherwise the type-check may pass (via any) but runtime will fail with an “undefined argument” error.


🏁 Script executed:

#!/bin/bash
# Verify every call passes three args
rg --no-heading -n $'\\.process\\(' | gawk '/process\\(/ && NF {print}'

Length of output: 128


Refined signature‐drift verification – ensure every call to processorService.process passes three arguments:


🏁 Script executed:

#!/bin/bash
# List all calls to processorService.process and flag any with ≠3 args
rg --no-heading -n 'processorService\.process\(' | while IFS=: read -r file line text; do
  # extract argument list between the first pair of parentheses
  args=$(echo "$text" | sed -E 's/.*processorService\.process\((.*)\).*/\1/')
  # count commas (args = commas+1)
  count=$(( $(grep -o "," <<<"$args" | wc -l) + 1 ))
  if [ "$count" -ne 3 ]; then
    echo "Incorrect arg count in $file:$line → found $count args"
  fi
done

Length of output: 782


Let’s inspect the processorService.process call in moderation.service.ts to confirm its argument list:


🏁 Script executed:

#!/bin/bash
# Show 3 lines before/after each processorService.process usage
rg -n -C3 'processorService\.process' apps/api/src/services/moderation.service.ts

Length of output: 367


Add the missing feedId argument in moderation.service.ts

The call to processorService.process in apps/api/src/services/moderation.service.ts only passes two arguments but the signature now requires three. Update it to include the feedId.

• File: apps/api/src/services/moderation.service.ts
Lines: 166–169

- await this.processorService.process(
-   submission,
-   feedConfig.outputs.stream,
- );
+ await this.processorService.process(
+   submission,
+   feedConfig.outputs.stream,
+   feedEntry.feedId,
+ );

Likely an incorrect or invalid review comment.

apps/api/src/services/distribution.service.ts (1)

21-37:

Details

❓ Verification inconclusive

New mandatory feedId – compile vs. runtime safety

The extra parameter is great for secret hydration, but any downstream caller missing it will now silently compile if their feedId is typed as any/unknown.
Run a quick repo-wide grep to guarantee there are zero 2-arg invocations left.


🏁 Script executed:

#!/bin/bash
# Expect no matches
rg --no-heading -n $'distributeContent\\([^,]+,[^,]+\\)' | grep -v ',[^,]+,[^,]+'

Length of output: 80


To catch any calls with exactly two arguments (including multi-line invocations), let’s use an AST-based search:


🏁 Script executed:

#!/bin/bash
# Find any distributeContent calls with exactly two args
ast-grep --pattern $'$.distributeContent($_, $_)'

Length of output: 50


Verify zero 2-arg distributeContent calls
The new feedId parameter is mandatory; any call still passing only two arguments (especially if typed as any/unknown) will compile but fail at runtime. Please run a repo-wide search to ensure there are no invocations with fewer than three arguments:

rg -n "distributeContent\s*\(" | grep -E -v "distributeContent\([^,]+,[^,]+,[^,]+\)"

If you find any matches, update them to include the feedId.

apps/api/src/services/transformation.service.ts (1)

10-11: .js extension import – verify path after emit

The switch to ./plugin.service.js only works if:

  1. module is NodeNext/Node16 and
  2. outDir preserves relative structure.

If any consumer compiles to CJS (see shared-db change), this path will resolve incorrectly. Double-check the emitted file layout or revert to extension-less import and rely on TS path mapping.

apps/secret-service/.dockerignore (1)

1-42: Concise & well-scoped .dockerignore
The ignore list covers the usual heavyweight & developer-only artifacts and keeps the production image lean. No issues spotted.

apps/api/src/utils/service-provider.ts (1)

22-220: Prettier check failed – run formatter
CI flagged service-provider.ts. A quick pnpm prettier --write apps/api/src/utils/service-provider.ts (or equivalent) will unblock the pipeline.

packages/shared-db/src/schema/secrets.ts (1)

1-55: Prettier check failing – run formatter

CI flagged this file. Running prettier --write packages/shared-db/src/schema/secrets.ts will fix spacing and trailing commas (e.g. after spread ...timestamps).

🧰 Tools
🪛 GitHub Actions: CI

[warning] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

packages/shared-db/src/validators.ts (1)

180-191: Missing formatting & trailing newline

The same Prettier failure applies here. Formatting will also add a newline at EOF, keeping git diffs clean.

prettier --write packages/shared-db/src/validators.ts
apps/secret-service/src/services/secret-store.service.ts (1)

27-127: Well-implemented secret storage service.

The implementation demonstrates good practices:

  • Proper use of upsert pattern for idempotent operations
  • Comprehensive error handling and logging
  • Buffer type validation before decryption
  • Returns null instead of throwing on retrieval failures
apps/secret-service/src/index.ts (2)

113-126: Excellent security measure for protecting private keys.

The check to prevent retrieval of private keys through the plaintext endpoint is a crucial security control. This ensures private keys can only be used for signing operations.


203-204: Good validation logic for plaintextValue.

Using plaintextValue === undefined instead of a falsy check correctly allows empty strings as valid secret values while rejecting undefined.

apps/secret-service/Dockerfile (3)

11-23: Validate the prune scopes include all dependencies

The turbo prune --scope=@curatedotfun/secret-service command must capture all direct workspace dependencies (e.g., shared-db, types, utils). Please verify and, if needed, add additional --scope flags or update your workspace configuration.


66-74: Ignore Hadolint DL3021 false positive on COPY

The flagged COPY commands use exactly two arguments (source and destination), which is valid Docker syntax. You can safely disregard the DL3021 warning in this context.


79-80: Verify pnpm filter triple-dot syntax

Ensure that --filter=@curatedotfun/secret-service... (with the trailing ...) correctly includes transitive workspace dependencies during the production install.

Comment on lines +2 to +15
// "extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"noEmit": false, // This package needs to emit JS and declaration files
"declaration": true, // Generate .d.ts files
"declarationMap": true, // Generate sourcemaps for .d.ts files
"composite": true, // Required for project references and building this package
"module": "ESNext",
"moduleResolution": "bundler",
"baseUrl": "."
"module": "CommonJS",
"moduleResolution": "Node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Configuration drift from monorepo baseline

Commenting out the "extends" line and flipping to "module": "CommonJS" / "moduleResolution": "Node" breaks the prior ESM/bundler alignment that other packages still rely on.
This will:

  1. Force consumers that compile as ESM to pull in CommonJS artifacts (node resolution hates mixed graphs).
  2. Duplicate compiler options that may go stale compared to the root config.

Unless you ​require CJS emission here, keep the inheritance and just override the handful of flags:

-// "extends": "../../tsconfig.json",
+"extends": "../../tsconfig.json",
   "compilerOptions": {
-    "module": "CommonJS",
-    "moduleResolution": "Node",
+    "module": "CommonJS",             // if absolutely needed
+    "moduleResolution": "Node",

Add a comment explaining why this package is special to avoid accidental re-alignment later.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// "extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"noEmit": false, // This package needs to emit JS and declaration files
"declaration": true, // Generate .d.ts files
"declarationMap": true, // Generate sourcemaps for .d.ts files
"composite": true, // Required for project references and building this package
"module": "ESNext",
"moduleResolution": "bundler",
"baseUrl": "."
"module": "CommonJS",
"moduleResolution": "Node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"noEmit": false, // This package needs to emit JS and declaration files
"declaration": true, // Generate .d.ts files
"declarationMap": true, // Generate sourcemaps for .d.ts files
"composite": true, // Required for project references and building this package
"module": "CommonJS", // if absolutely needed
"moduleResolution": "Node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
🤖 Prompt for AI Agents
In packages/shared-db/tsconfig.json lines 2 to 15, the "extends" line is
commented out and the module settings are changed to CommonJS, causing
configuration drift from the monorepo baseline and breaking ESM alignment.
Restore the "extends" line to inherit from the root tsconfig.json, override only
the necessary compilerOptions like "rootDir", "outDir", and "declaration" flags,
and add a comment explaining why this package requires these specific overrides
to prevent accidental future changes.

Comment on lines +5 to +9
const pool = new Pool({
connectionString: process.env.DATABASE_URL!,
});
const db: DB = drizzle(pool, { schema });

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fail-fast env validation

Using process.env.DATABASE_URL! will crash after the Pool is constructed (or worse, hang).
Guard early:

-const pool = new Pool({
-  connectionString: process.env.DATABASE_URL!,
-});
+const { DATABASE_URL } = process.env;
+if (!DATABASE_URL) {
+  throw new Error("DATABASE_URL env var is required for Secret Service DB");
+}
+const pool = new Pool({ connectionString: DATABASE_URL });

Also expose a helper to gracefully pool.end() during service shutdown to avoid connection leaks in tests.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const pool = new Pool({
connectionString: process.env.DATABASE_URL!,
});
const db: DB = drizzle(pool, { schema });
const { DATABASE_URL } = process.env;
if (!DATABASE_URL) {
throw new Error("DATABASE_URL env var is required for Secret Service DB");
}
const pool = new Pool({ connectionString: DATABASE_URL });
const db: DB = drizzle(pool, { schema });
🤖 Prompt for AI Agents
In apps/secret-service/src/db/index.ts around lines 5 to 9, the code uses
process.env.DATABASE_URL! without checking if it is defined, which can cause
crashes or hangs after Pool construction. Add an early guard to validate that
DATABASE_URL is set before creating the Pool, throwing a clear error if missing.
Additionally, export a helper function that calls pool.end() to allow graceful
shutdown of the database connection, preventing connection leaks during tests or
service shutdown.

Comment on lines +37 to +48
if (!env.SECRET_SERVICE_URL || !env.SECRET_SERVICE_INTERNAL_API_KEY) {
logger.error(
"ServiceProvider: SECRET_SERVICE_URL or SECRET_SERVICE_INTERNAL_API_KEY is not defined. SecretServiceApiClient may not function correctly.",
);
}
const secretServiceApiClient = new SecretServiceApiClient(
env.SECRET_SERVICE_URL!,
env.SECRET_SERVICE_INTERNAL_API_KEY!,
logger,
);
this.services.set("secretServiceApiClient", secretServiceApiClient);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Runtime will still crash if the env vars are missing
You log an error but immediately bypass it with non-null assertions, so the constructor will throw later anyway. If you want a graceful degradation, guard the instantiation:

-if (!env.SECRET_SERVICE_URL || !env.SECRET_SERVICE_INTERNAL_API_KEY) {
-  logger.error(
-    "ServiceProvider: SECRET_SERVICE_URL or SECRET_SERVICE_INTERNAL_API_KEY is not defined. SecretServiceApiClient may not function correctly.",
-  );
-}
-const secretServiceApiClient = new SecretServiceApiClient(
-  env.SECRET_SERVICE_URL!, 
-  env.SECRET_SERVICE_INTERNAL_API_KEY!,
-  logger,
-);
-this.services.set("secretServiceApiClient", secretServiceApiClient);
+if (env.SECRET_SERVICE_URL && env.SECRET_SERVICE_INTERNAL_API_KEY) {
+  const secretServiceApiClient = new SecretServiceApiClient(
+    env.SECRET_SERVICE_URL,
+    env.SECRET_SERVICE_INTERNAL_API_KEY,
+    logger,
+  );
+  this.services.set("secretServiceApiClient", secretServiceApiClient);
+} else {
+  logger.error(
+    "ServiceProvider: Missing SECRET_SERVICE_URL or SECRET_SERVICE_INTERNAL_API_KEY – SecretServiceApiClient disabled.",
+  );
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!env.SECRET_SERVICE_URL || !env.SECRET_SERVICE_INTERNAL_API_KEY) {
logger.error(
"ServiceProvider: SECRET_SERVICE_URL or SECRET_SERVICE_INTERNAL_API_KEY is not defined. SecretServiceApiClient may not function correctly.",
);
}
const secretServiceApiClient = new SecretServiceApiClient(
env.SECRET_SERVICE_URL!,
env.SECRET_SERVICE_INTERNAL_API_KEY!,
logger,
);
this.services.set("secretServiceApiClient", secretServiceApiClient);
if (env.SECRET_SERVICE_URL && env.SECRET_SERVICE_INTERNAL_API_KEY) {
const secretServiceApiClient = new SecretServiceApiClient(
env.SECRET_SERVICE_URL,
env.SECRET_SERVICE_INTERNAL_API_KEY,
logger,
);
this.services.set("secretServiceApiClient", secretServiceApiClient);
} else {
logger.error(
"ServiceProvider: Missing SECRET_SERVICE_URL or SECRET_SERVICE_INTERNAL_API_KEY – SecretServiceApiClient disabled.",
);
}
🤖 Prompt for AI Agents
In apps/api/src/utils/service-provider.ts around lines 37 to 48, the code logs
an error if SECRET_SERVICE_URL or SECRET_SERVICE_INTERNAL_API_KEY are missing
but then uses non-null assertions to instantiate SecretServiceApiClient, which
will cause a runtime crash. To fix this, add a conditional check to only create
and set secretServiceApiClient if both environment variables are defined,
preventing the constructor from being called with undefined values and allowing
graceful degradation.

Comment on lines +3 to +22
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"noEmit": false,
"module": "NodeNext",
"moduleResolution": "NodeNext",
"target": "ESNext",
"strict": true,
"baseUrl": ".",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"verbatimModuleSyntax": true,
"types": ["node"],
"paths": {
"@curatedotfun/shared-db": ["../../packages/shared-db/src"],
"*": ["src/*"]
}
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enable composite & incremental for project-references build

Because this project is referenced by packages/shared-db, the recommended pattern for a TypeScript monorepo is to mark every referenced tsconfig.json as composite (and usually incremental) so that tsc -b works end-to-end and emits build-info files for fast rebuilds.

   "compilerOptions": {
+    "composite": true,
+    "incremental": true,
     "rootDir": "./src",
     "outDir": "./dist",

Without these flags, tsc -b will silently skip building this sub-project and type-checking may become inconsistent.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist",
"noEmit": false,
"module": "NodeNext",
"moduleResolution": "NodeNext",
"target": "ESNext",
"strict": true,
"baseUrl": ".",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"verbatimModuleSyntax": true,
"types": ["node"],
"paths": {
"@curatedotfun/shared-db": ["../../packages/shared-db/src"],
"*": ["src/*"]
}
},
"compilerOptions": {
"composite": true,
"incremental": true,
"rootDir": "./src",
"outDir": "./dist",
"noEmit": false,
"module": "NodeNext",
"moduleResolution": "NodeNext",
"target": "ESNext",
"strict": true,
"baseUrl": ".",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"verbatimModuleSyntax": true,
"types": ["node"],
"paths": {
"@curatedotfun/shared-db": ["../../packages/shared-db/src"],
"*": ["src/*"]
}
},
🤖 Prompt for AI Agents
In apps/secret-service/tsconfig.json around lines 3 to 22, the compilerOptions
section lacks the "composite" and "incremental" flags needed for proper
TypeScript project references. Add "composite": true and "incremental": true to
the compilerOptions to enable correct build behavior with tsc -b, ensuring this
sub-project is built and type-checked consistently within the monorepo.

Comment on lines +10 to +23
// Define a custom type for bytea, assuming it will be handled as Buffer in JS/TS
const byteaType = customType<{ data: Buffer; driverData: string }>({
dataType() {
return "bytea";
},
toDriver(value: Buffer): string {
// Convert Buffer to hex string for storage, or let the driver handle it
// For node-postgres, it can often handle Buffers directly.
// If direct Buffer handling is problematic, convert to hex: value.toString('hex')
// However, for now, let's assume the driver handles Buffer correctly.
// If not, this mapping function would be: `return '\\x' + value.toString('hex');`
return value as any;
},
fromDriver(value: string | Buffer): Buffer {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

customType generic mismatched – Buffer returned where string expected

driverData is declared as string, yet toDriver returns a Buffer, forcing an as any cast and defeating type-safety. Change the generic to reflect reality (or convert to hex).

-const byteaType = customType<{ data: Buffer; driverData: string }>({
+const byteaType = customType<{ data: Buffer; driverData: Buffer }>({
 ...
-  toDriver(value: Buffer): string {
-    return value as any;
+  toDriver(value: Buffer): Buffer {
+    return value;
   },

This removes the unsafe cast and prevents accidental misuse.

🤖 Prompt for AI Agents
In packages/shared-db/src/schema/secrets.ts around lines 10 to 23, the generic
type for customType incorrectly declares driverData as string while toDriver
returns a Buffer, causing an unsafe cast. Fix this by updating the generic type
to have driverData as Buffer instead of string, or alternatively convert the
Buffer to a hex string in toDriver to match the string type. This will remove
the unsafe cast and ensure type safety.

@@ -0,0 +1,127 @@
import {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix code formatting issues.

The pipeline indicates formatting issues in this file.

Run the following command to fix formatting:

pnpm prettier --write apps/secret-service/src/services/secret-store.service.ts
🧰 Tools
🪛 GitHub Actions: CI

[warning] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

🤖 Prompt for AI Agents
In apps/secret-service/src/services/secret-store.service.ts at line 1, there are
code formatting issues detected by the pipeline. To fix this, run the command
"pnpm prettier --write apps/secret-service/src/services/secret-store.service.ts"
to automatically format the file according to the project's style guidelines.

Comment on lines +168 to +169
const keyPair = KeyPair.fromString(privateKey as any); // Cast to satisfy KeyPairString type
const signature = keyPair.sign(new TextEncoder().encode(payload));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid using as any cast for type safety.

The as any cast bypasses TypeScript's type checking. Consider properly typing the privateKey or using a type assertion that's more specific.

-      const keyPair = KeyPair.fromString(privateKey as any); // Cast to satisfy KeyPairString type
+      // Ensure privateKey is properly typed or use a more specific type assertion
+      const keyPair = KeyPair.fromString(privateKey);

If the type mismatch is due to the KeyPair API, consider:

  1. Updating the type definitions
  2. Using a more specific type assertion
  3. Adding runtime validation before the call
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const keyPair = KeyPair.fromString(privateKey as any); // Cast to satisfy KeyPairString type
const signature = keyPair.sign(new TextEncoder().encode(payload));
// Ensure privateKey is properly typed or use a more specific type assertion
const keyPair = KeyPair.fromString(privateKey);
const signature = keyPair.sign(new TextEncoder().encode(payload));
🤖 Prompt for AI Agents
In apps/secret-service/src/index.ts around lines 168 to 169, avoid using the `as
any` cast on `privateKey` to maintain type safety. Instead, ensure `privateKey`
is properly typed as a string or the expected KeyPairString type before this
code. If the KeyPair API types are incorrect, update the type definitions
accordingly or use a more specific type assertion that matches the expected
input. Additionally, add runtime validation to confirm `privateKey` is valid
before calling `KeyPair.fromString`.

Comment on lines +79 to +82
logger.warn(
`Unauthorized access attempt to secret-service. Provided key: ${providedKey ? providedKey.substring(0, 5) + "..." : "None"}`,
);
return c.json({ error: "Unauthorized" }, 401);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Security: Avoid logging partial API keys.

Logging even partial API keys (first 5 characters) could aid attackers in brute-force attempts or social engineering.

-    logger.warn(
-      `Unauthorized access attempt to secret-service. Provided key: ${providedKey ? providedKey.substring(0, 5) + "..." : "None"}`,
-    );
+    logger.warn(
+      `Unauthorized access attempt to secret-service. API key provided: ${providedKey ? "Yes" : "No"}`,
+    );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
logger.warn(
`Unauthorized access attempt to secret-service. Provided key: ${providedKey ? providedKey.substring(0, 5) + "..." : "None"}`,
);
return c.json({ error: "Unauthorized" }, 401);
logger.warn(
`Unauthorized access attempt to secret-service. API key provided: ${providedKey ? "Yes" : "No"}`,
);
return c.json({ error: "Unauthorized" }, 401);
🤖 Prompt for AI Agents
In apps/secret-service/src/index.ts around lines 79 to 82, the code logs the
first 5 characters of the provided API key during unauthorized access attempts,
which poses a security risk. Remove the partial API key from the log message
entirely and replace it with a generic message that does not reveal any part of
the key to prevent aiding attackers.

Comment on lines +194 to +202
// The spec mentions publicKey here, but SecretStoreService.setSecret doesn't use it.
// If publicKey needs to be stored, the service and schema would need an update.
// For now, matching the service method.
const { feedId, keyName, plaintextValue } = await c.req.json<{
feedId: string;
keyName: string;
plaintextValue: string;
publicKey?: string;
}>();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Unused publicKey parameter in API design.

The comment indicates that publicKey is accepted in the request but not used by the SecretStoreService. This creates confusion about the API contract.

Either remove the unused parameter from the API:

-    const { feedId, keyName, plaintextValue } = await c.req.json<{
+    const { feedId, keyName, plaintextValue } = await c.req.json<{
       feedId: string;
       keyName: string;
       plaintextValue: string;
-      publicKey?: string;
     }>();

Or update the SecretStoreService to handle the publicKey parameter if it's intended for future use.

🤖 Prompt for AI Agents
In apps/secret-service/src/index.ts around lines 194 to 202, the publicKey
parameter is extracted from the request JSON but not used in the
SecretStoreService.setSecret method, causing confusion about the API contract.
To fix this, either remove the publicKey parameter from the request parsing and
related API definitions if it is not needed, or update the SecretStoreService
and its schema to accept and handle the publicKey parameter properly if it is
intended for future use.

Comment on lines +27 to +63
app.use("*", async (c, next) => {
// Service initialization logic (lazy, on first request)
// This ensures env vars are loaded via Hono's adapter before services use them.
if (!encryptionService) {
const { ENCRYPTION_MASTER_KEY, DATABASE_URL } = env<AppEnv>(c);
if (!ENCRYPTION_MASTER_KEY) {
logger.error(
"FATAL: ENCRYPTION_MASTER_KEY is not defined in the environment.",
);
return c.json(
{ error: "Server configuration error: Missing master key." },
500,
);
}
if (!DATABASE_URL) {
// Though db/index.js checks, good to be defensive
logger.error(
"FATAL: DATABASE_URL is not defined in the environment for service initialization.",
);
return c.json(
{ error: "Server configuration error: Missing database URL." },
500,
);
}
try {
encryptionService = new EncryptionService(ENCRYPTION_MASTER_KEY);
secretStoreService = new SecretStoreService(
db,
encryptionService,
logger,
);
logger.info("Services initialized successfully.");
} catch (error) {
logger.error("FATAL: Failed to initialize services.", { error });
return c.json({ error: "Server initialization failed." }, 500);
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential race condition in service initialization.

The lazy initialization pattern could lead to race conditions if multiple requests arrive simultaneously before the services are initialized. Multiple concurrent requests could trigger multiple initialization attempts.

Consider initializing services once during startup or using a proper synchronization mechanism:

-// Initialize services - these will be set in the 'request' hook or a startup function
-let encryptionService: EncryptionService;
-let secretStoreService: SecretStoreService;
+// Initialize services with proper synchronization
+let encryptionService: EncryptionService;
+let secretStoreService: SecretStoreService;
+let initializationPromise: Promise<void> | null = null;

 // Middleware for API Key Authentication & Service Initialization
 app.use("*", async (c, next) => {
   // Service initialization logic (lazy, on first request)
   // This ensures env vars are loaded via Hono's adapter before services use them.
   if (!encryptionService) {
+    if (!initializationPromise) {
+      initializationPromise = (async () => {
         const { ENCRYPTION_MASTER_KEY, DATABASE_URL } = env<AppEnv>(c);
         // ... rest of initialization logic
+      })();
+    }
+    try {
+      await initializationPromise;
+    } catch (error) {
+      return c.json({ error: "Server initialization failed." }, 500);
+    }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
app.use("*", async (c, next) => {
// Service initialization logic (lazy, on first request)
// This ensures env vars are loaded via Hono's adapter before services use them.
if (!encryptionService) {
const { ENCRYPTION_MASTER_KEY, DATABASE_URL } = env<AppEnv>(c);
if (!ENCRYPTION_MASTER_KEY) {
logger.error(
"FATAL: ENCRYPTION_MASTER_KEY is not defined in the environment.",
);
return c.json(
{ error: "Server configuration error: Missing master key." },
500,
);
}
if (!DATABASE_URL) {
// Though db/index.js checks, good to be defensive
logger.error(
"FATAL: DATABASE_URL is not defined in the environment for service initialization.",
);
return c.json(
{ error: "Server configuration error: Missing database URL." },
500,
);
}
try {
encryptionService = new EncryptionService(ENCRYPTION_MASTER_KEY);
secretStoreService = new SecretStoreService(
db,
encryptionService,
logger,
);
logger.info("Services initialized successfully.");
} catch (error) {
logger.error("FATAL: Failed to initialize services.", { error });
return c.json({ error: "Server initialization failed." }, 500);
}
}
// Initialize services with proper synchronization
let encryptionService: EncryptionService;
let secretStoreService: SecretStoreService;
let initializationPromise: Promise<void> | null = null;
// Middleware for API Key Authentication & Service Initialization
app.use("*", async (c, next) => {
// Service initialization logic (lazy, on first request)
// This ensures env vars are loaded via Hono's adapter before services use them.
if (!encryptionService) {
if (!initializationPromise) {
initializationPromise = (async () => {
const { ENCRYPTION_MASTER_KEY, DATABASE_URL } = env<AppEnv>(c);
if (!ENCRYPTION_MASTER_KEY) {
logger.error(
"FATAL: ENCRYPTION_MASTER_KEY is not defined in the environment.",
);
return c.json(
{ error: "Server configuration error: Missing master key." },
500,
);
}
if (!DATABASE_URL) {
// Though db/index.js checks, good to be defensive
logger.error(
"FATAL: DATABASE_URL is not defined in the environment for service initialization.",
);
return c.json(
{ error: "Server configuration error: Missing database URL." },
500,
);
}
try {
encryptionService = new EncryptionService(ENCRYPTION_MASTER_KEY);
secretStoreService = new SecretStoreService(
db,
encryptionService,
logger,
);
logger.info("Services initialized successfully.");
} catch (error) {
logger.error("FATAL: Failed to initialize services.", { error });
throw error;
}
})();
}
try {
await initializationPromise;
} catch (error) {
return c.json({ error: "Server initialization failed." }, 500);
}
}
// Proceed with authentication, routing, etc.
return next();
});
🤖 Prompt for AI Agents
In apps/secret-service/src/index.ts between lines 27 and 63, the current lazy
initialization of encryptionService and secretStoreService inside the middleware
can cause race conditions when multiple requests trigger initialization
concurrently. To fix this, move the service initialization to the application
startup phase before handling requests, or implement a synchronization mechanism
such as a mutex or a promise lock to ensure only one initialization occurs at a
time and other requests wait for it to complete.

Base automatically changed from staging to main June 20, 2025 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants