Skip to content

Pass ENOTIFY_INTERNAL_TOKEN through to vapi - #1710

Closed
feruzm wants to merge 1 commit into
developfrom
feat/enotify-internal-token
Closed

Pass ENOTIFY_INTERNAL_TOKEN through to vapi#1710
feruzm wants to merge 1 commit into
developfrom
feat/enotify-internal-token

Conversation

@feruzm

@feruzm feruzm commented Sep 1, 2026

Copy link
Copy Markdown
Member

Closes a gap in my own change, found while working out where the secret actually needs to be set.

ecency/vision-api#91 (merged, deployed) reads ENOTIFY_INTERNAL_TOKEN to unlock a user's own complete notification feed from enotify. But nothing ever set it: the variable was never added to the compose files or forwarded by the deploy workflows, so vapi would have read an empty string forever and never sent the header.

What this does

Wired exactly like SSR_INTERNAL_SECRET, the most recent secret of the same shape:

file change
docker-compose.production.yml declared on the vapi service
docker-compose.yml (staging) same
master.yml env map, ssh envs: list, and export — in both the EU and US deploy jobs
staging.yml the same three places

Only vapi gets it. The web service does not talk to enotify.

Setting it by hand on the running service would not have worked either: a stack deploy from this repo resets the full service spec of every service in the stack, so it has to live here.

Required before this helps

An ENOTIFY_INTERNAL_TOKEN repository secret, matching [APP] INTERNAL_TOKEN in enotify's config.ini.

⚠️ enotify fails closed. Until both sides carry the same value, every user quietly loses favorites, bookmarks, Points transfers and the aggregates from their own notification list. That is the designed behaviour, not a bug, but it means the two must be set together.

Deploy order: set the enotify config value and this repository secret → deploy this → deploy enotify.

Verification

All four YAML files parse. Asserted that all three wiring points are present in each deploy job (2 in master, 1 in staging), that the vapi service carries the variable, and that the web service does not.

Gap in my own change. ecency/vision-api#91 reads ENOTIFY_INTERNAL_TOKEN to unlock
a user's own complete notification feed from enotify, but nothing ever set it:
the variable was never added to the compose files or forwarded by the deploy
workflows, so vapi would have read an empty string forever.

Wired exactly like SSR_INTERNAL_SECRET, which is the most recent secret of the
same shape: declared on the vapi service in both compose files, and forwarded in
all three places each deploy job needs it (the env map, the ssh envs list and the
export before the stack deploy), across both regions in master.yml and staging.

Only the vapi service gets it. The web service does not talk to enotify.

Setting it by hand on the running service would not have worked either: a stack
deploy from this repo resets the full service spec of every service in the stack,
so it has to live here.

Requires the ENOTIFY_INTERNAL_TOKEN repository secret, matching [APP]
INTERNAL_TOKEN in enotify's config.ini. enotify fails closed, so until both sides
carry the same value every user quietly loses favorites, bookmarks, Points
transfers and the aggregates from their own notification list.
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Forward ENOTIFY_INTERNAL_TOKEN to vapi deployments

🐞 Bug fix ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

AI Description

• Forward ENOTIFY_INTERNAL_TOKEN through production and staging deployment workflows.
• Inject the token only into vapi Compose services.
• Restore authenticated access to users' complete enotify feeds.
Diagram

graph TD
  S["Repository Secret"] -->|"loads"| P["Production Jobs"] -->|"forwards"| H["SSH Environment"] -->|"exports"| C["Compose Config"] -->|"injects"| V["VAPI Service"] -->|"authenticates"| E["Enotify API"]
  S -->|"loads"| T["Staging Job"] -->|"forwards"| H
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Fail-fast secret validation
  • ➕ Prevents deployments that silently omit the token
  • ➕ Immediately identifies a missing repository secret
  • ➖ Cannot verify that the token matches enotify's configured value
  • ➖ Requires coordinated handling if tokenless deployments must remain possible
2. Docker Swarm secrets
  • ➕ Avoids exposing the token as a conventional container environment variable
  • ➕ Provides explicit secret lifecycle management
  • ➖ Requires vapi to support file-based secret loading
  • ➖ Introduces disproportionate migration and operational complexity for this fix

Recommendation: The PR's environment-variable propagation is the best immediate approach because it matches vapi's existing contract and established SSR_INTERNAL_SECRET deployment pattern. Add non-empty fail-fast assertions to all deployment jobs if tokenless operation is not intentionally supported; defer Swarm secrets to a broader secret-management migration.

Files changed (4) +19 / -3

Other (4) +19 / -3
master.ymlForward enotify token through both production regions +6/-2

Forward enotify token through both production regions

• Adds the repository secret to the EU and US deployment environments, SSH forwarding lists, and remote exports. This makes the token available when each production stack renders its Compose configuration.

.github/workflows/master.yml

staging.ymlForward enotify token through staging deployment +3/-1

Forward enotify token through staging deployment

• Adds the token to the staging workflow environment, SSH forwarding list, and remote export so staging Compose receives it.

.github/workflows/staging.yml

docker-compose.production.ymlInject enotify token into production vapi +5/-0

Inject enotify token into production vapi

• Declares ENOTIFY_INTERNAL_TOKEN on the production vapi service and documents its fail-closed notification behavior. The web service remains unaffected.

apps/web/docker-compose.production.yml

docker-compose.ymlInject enotify token into staging vapi +5/-0

Inject enotify token into staging vapi

• Declares ENOTIFY_INTERNAL_TOKEN on the staging vapi service and documents why complete user notification feeds require it. The token is not exposed to the web service.

apps/web/docker-compose.yml

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Missing token deploys silently 🐞 Bug ☼ Reliability
Description
The bare Compose passthrough accepts an absent or empty ENOTIFY_INTERNAL_TOKEN, so deployments
succeed while vapi silently omits favorites, bookmarks, Points transfers, and notification
aggregates. This also lets a later missing-secret deployment reset a previously working service to
the degraded state without any CI failure.
Code

apps/web/docker-compose.production.yml[27]

+      - ENOTIFY_INTERNAL_TOKEN
Evidence
Both Compose files explicitly state that an unset token removes multiple notification types, yet
line 27 uses an optional bare passthrough. The workflows render these files and deploy the resulting
stack without validating this token; the repository already demonstrates required Compose
interpolation for HIVESEARCHER_ORIGIN_IP.

apps/web/docker-compose.production.yml[11-27]
apps/web/docker-compose.yml[11-27]
.github/workflows/master.yml[174-192]
.github/workflows/master.yml[303-333]
.github/workflows/staging.yml[172-188]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
An unset or empty `ENOTIFY_INTERNAL_TOKEN` currently passes through Compose without failing, allowing a green deployment that disables parts of users' notification feeds.

## Issue Context
Both production and staging Compose configurations describe this token as necessary for the complete feed. Use required-variable interpolation, consistent with the existing `HIVESEARCHER_ORIGIN_IP` handling, so Compose rendering fails before stack deployment when the token is absent or empty.

## Fix Focus Areas
- apps/web/docker-compose.production.yml[23-27]
- apps/web/docker-compose.yml[23-27]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: ⚖️ Balanced: This is a security-sensitive secret-propagation change across deployment workflows and Compose service configuration, with multiple independent wiring points where omissions or misrouting could affect runtime behavior.

Grey Divider

Tip of the day
💡 Did you know, you can describe a rule in plain language on the Rules page and Qodo drafts it for you

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

# notification feed. enotify defaults to chain-derived activity only and
# fails closed, so unset means every user silently loses favorites,
# bookmarks, Points transfers and the aggregates from their own list.
- ENOTIFY_INTERNAL_TOKEN

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Missing token deploys silently 🐞 Bug ☼ Reliability

The bare Compose passthrough accepts an absent or empty ENOTIFY_INTERNAL_TOKEN, so deployments
succeed while vapi silently omits favorites, bookmarks, Points transfers, and notification
aggregates. This also lets a later missing-secret deployment reset a previously working service to
the degraded state without any CI failure.
Agent Prompt
## Issue description
An unset or empty `ENOTIFY_INTERNAL_TOKEN` currently passes through Compose without failing, allowing a green deployment that disables parts of users' notification feeds.

## Issue Context
Both production and staging Compose configurations describe this token as necessary for the complete feed. Use required-variable interpolation, consistent with the existing `HIVESEARCHER_ORIGIN_IP` handling, so Compose rendering fails before stack deployment when the token is absent or empty.

## Fix Focus Areas
- apps/web/docker-compose.production.yml[23-27]
- apps/web/docker-compose.yml[23-27]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d343c27d6e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

export SEO_CRON_SECRET=$SEO_CRON_SECRET
export TURNSTILE_SECRET=$TURNSTILE_SECRET
export SSR_INTERNAL_SECRET=$SSR_INTERNAL_SECRET
export ENOTIFY_INTERNAL_TOKEN=$ENOTIFY_INTERNAL_TOKEN

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reject an empty enotify token before deploying

When ENOTIFY_INTERNAL_TOKEN is missing from the repository secrets, this export still succeeds and the production compose render deploys vapi with an empty token. As the new compose comment states, vapi then fails closed and silently omits favorites, bookmarks, Points transfers, and aggregates for every user, while the workflow remains green. Add a nonempty preflight check in both production deploy jobs, analogous to the adjacent newsletter checks; staging should at least fail or warn explicitly as intended.

Useful? React with 👍 / 👎.

@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 34 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: c4f567e5-c508-4ba8-900d-04245c0e41d0

📥 Commits

Reviewing files that changed from the base of the PR and between 4234a8b and d343c27.

📒 Files selected for processing (4)
  • .github/workflows/master.yml
  • .github/workflows/staging.yml
  • apps/web/docker-compose.production.yml
  • apps/web/docker-compose.yml

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

Comment @coderabbitai help to get the list of available commands.

@feruzm

feruzm commented Sep 1, 2026

Copy link
Copy Markdown
Member Author

Superseded by ecency/enotify-py#23, which drops the shared secret entirely in favour of trusting the private network position that api-proxy already uses. No repository secret, no compose change, no deploy ordering to get wrong.

Reusing PRIVATE_API_AUTH was the first thing I checked, since vapi already sends it upstream on every call. It decodes to a single secret User-Agent, and that string appears 53,360 times in the enotify box's current access log and 930,635 times in its rotated ones, before counting api-proxy and Cloudflare. Not somewhere to put a credential that unlocks private notification data.

Closing this unmerged unless you would rather keep the token path as the primary.

@feruzm

feruzm commented Sep 1, 2026

Copy link
Copy Markdown
Member Author

Note for anyone reading the two bot findings above: both flag that a missing ENOTIFY_INTERNAL_TOKEN would deploy silently and strip every user's own private notifications. They are correct, and that ordering hazard is precisely why this approach was abandoned.

ecency/enotify-py#23 removes the secret entirely in favour of trusting the specific api-proxy host, so there is no token to forget, no repository secret, no compose passthrough and no deploy ordering at all. This PR should be closed unmerged rather than fixed.

@feruzm feruzm closed this Sep 1, 2026
@feruzm
feruzm deleted the feat/enotify-internal-token branch September 1, 2026 19:14
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.

1 participant