Skip to content

refactor(integrations): store the GroupMe access token as a connector secret ref (TASK-539) - #3004

Merged
lilyshen0722 merged 2 commits into
mainfrom
fix/task-539-groupme-slack-secrets
Oct 30, 2026
Merged

lilyshen0722 merged 2 commits into
mainfrom
fix/task-539-groupme-slack-secrets

Conversation

@lilyshen0722

@lilyshen0722 lilyshen0722 commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

@coderabbitai ignore

TASK-539. This moves the GroupMe access token onto the same connector-secret storage that the X and Instagram feed tokens use (#2692 / #2719). It also stops a Slack row from keeping accessToken / refreshToken config keys that no code reads.

Change

  • New connector-secret kind groupme-access-token. The row keeps config.accessTokenRef, which is declared in the schema, managed by the server, and left out of JSON projections like the other refs.
  • services/chatConnectorTokens.ts: the GroupMe and Slack counterparts of services/feedCredentials. The generic create and edit routes use it. A blank token on an edit keeps the stored token.
  • The agent integration-messages read for GroupMe resolves the ref. A missing secret is a 400 and any other failure is a 500.
  • connectorSecrets.putIfAbsent: an insert-only store that a migration uses, so it never replaces a secret written after it read the row.
  • scripts/migrate-chat-token-copies.ts: dry run by default, with counts-only output. It moves GroupMe tokens to the new storage, keeps any existing ref, and removes the unused keys on both types. Runbook: docs/runbooks/migrate-chat-token-copies.md.

Deploy order: deploy first, then the migration. The runbook has the steps.

Tests

  • chatConnectorTokens.test.js: routes against real Mongo.
  • migrateChatTokenCopies.test.js: dry run, apply, idempotency, an interleaved write, a missing key ring, and the CLI output.
  • agentsRuntime.integrations.messages.test.js: four GroupMe reader cases.
  • integrations-e2e.test.js: seeds its GroupMe row through the new storage.

The new cases were mutation-checked locally, and each fails against its mutant. The neighbouring suites pass, tsc stays at its baseline, and there are no new lint errors.

Tier 2.

🤖 Generated with Claude Code

@coderabbitai

This comment has been minimized.

coderabbitai[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as outdated.

samxu01 pushed a commit that referenced this pull request Oct 30, 2026
…t is a 400

CodeRabbit on #3004. The migration's import used the upserting put, so a
token a live PATCH stored between the migration's read and its write was
overwritten with the older plaintext. It now uses connectorSecrets.putIfAbsent
(insert on the unique (integrationId, kind) key); on a conflict the newer
secret and its ref win. The GroupMe reader maps only
ConnectorSecretNotFoundError to the missing-token 400; key-ring, decryption
and database errors reach the route's 500.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Keel <WyJrZWVsIiwiZGVmYXVsdCJd@agents.commonly.invalid>
Agent-Model: claude/claude-opus-5-5/high
@lilyshen0722

This comment has been minimized.

@lilyshen0722 lilyshen0722 changed the title fix(secrets): store GroupMe tokens in connectorSecrets, drop Slack copies (TASK-539) refactor(integrations): store the GroupMe access token as a connector secret ref (TASK-539) Oct 30, 2026
… secret ref (TASK-539)

- New connector-secret kind groupme-access-token. The integration row keeps
  config.accessTokenRef, declared in the schema, managed by the server and
  left out of JSON projections like the other refs.
- services/chatConnectorTokens.ts: the GroupMe and Slack counterparts of
  services/feedCredentials, used by the generic create and edit routes. A
  blank token on an edit keeps the stored one. Unused accessToken and
  refreshToken config keys are no longer kept on Slack rows.
- The agent integration-messages read for GroupMe resolves the ref. A
  missing secret is a 400; any other failure is a 500.
- connectorSecrets.putIfAbsent: an insert-only write for imports, so an
  import never replaces a secret written after it read the row.
- scripts/migrate-chat-token-copies.ts moves existing rows onto refs (dry
  run by default, counts-only output). Runbook:
  docs/runbooks/migrate-chat-token-copies.md. Deploy first, then migrate.

Written by Keel, a Commonly agent — https://commonly.me/v2/pods/6addc5e87f8fc798a6f2f5d2

Co-authored-by: Keel <WyJrZWVsIiwiZGVmYXVsdCJd@agents.commonly.invalid>
Agent-Model: claude/claude-opus-5-5/high
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4VWLEBieQcBxrJwwQF9Py
@samxu01
samxu01 force-pushed the fix/task-539-groupme-slack-secrets branch from 04d35af to dd1c9a3 Compare October 30, 2026 19:06
@lilyshen0722

Copy link
Copy Markdown
Contributor Author

Re #3004 (comment): fixed in 3bcf78e. The import now goes through connectorSecrets.putIfAbsent, which only inserts. If a live edit has already written the secret, the import keeps that newer value and drops the old copy, and moved counts only the rows it actually created. Covered by the interleaving case in migrateChatTokenCopies.test.js. The runbook note is in 04d35af.

Written by Keel, a Commonly agent — https://commonly.me/v2/pods/6addc5e87f8fc798a6f2f5d2

lilyshen0722

This comment was marked as outdated.

…k reads the ref only (TASK-539)

- groupmeService.fetchMessages rethrows a failed request as an error with
  the status only, and the integration-messages handler logs the message
  rather than the error object.
- slackProvider tokenFor resolves botTokenRef only; a row's own botToken
  copy is no longer a source.
- Direct unit tests for connectorSecrets.putIfAbsent (insert, and an
  existing pair returned with created false).

Written by Keel, a Commonly agent — https://commonly.me/v2/pods/6addc5e87f8fc798a6f2f5d2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
lilyshen0722

This comment was marked as outdated.

lilyshen0722

This comment was marked as outdated.

@lilyshen0722
lilyshen0722 added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit be0d948 Oct 30, 2026
31 checks passed
@lilyshen0722

Copy link
Copy Markdown
Contributor Author

Record for reviewers (not addressed to CodeRabbit): the review-body item at backend/routes/agentsRuntime.ts:3753 has no thread to reply in. It is fixed in 3bcf78e. Only a missing referenced secret takes the 400 path now; configuration, key-ring, decryption and database errors reach the route's 500 handler. The inline thread is answered in-thread.

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