feat(channels): add tracked bot setup links and signed callbacks - #1705
Merged
ctkm-aelf merged 7 commits intoSep 30, 2026
Merged
Conversation
📊 Code coverage
Gate: line coverage must stay at or above the threshold. Ratchet plan (W21): Backend → 55%, CLI → 50%, Frontend → 30% by quarter end. |
This was referenced Sep 30, 2026
ctkm-aelf
added a commit
that referenced
this pull request
Sep 30, 2026
* feat(auth): gate signup invitation codes behind default-on feature flag (#1690) Signup invitation codes are now an operator choice. The requirement is behind the global, default-on `auth:invitation-code` feature flag, which replaces the `INVITE_CODE_REQUIRED` environment variable and can be toggled in Admin > Feature Flags without a restart. - Enabled (default): email signup requires a valid code; browser social signup can redeem one; native social token exchange still rejects first-time signup. - Disabled: email and first-time social signup succeed without a code. - Flag is global only; scoped overrides are rejected. The backend resolves it on every signup attempt and /api/v1/public/config reports the effective state. - Invitation-code admin page, API and CLI are retained; the page states when codes are not required. Organization invitations are unchanged. - Rollout: deploy backend before frontend. Deployments with INVITE_CODE_REQUIRED=false must disable the flag to keep signup open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(rollup): record 2026-09-29 ctkm-1 rollup Records #1690 (default-on auth:invitation-code signup gate), its reviewed head and squash commit, the main sync to e96a507, rollout notes and verification. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(oauth): redesign consent screen to match connection flows (#1701) Rework the OAuth consent page into the centered card used by connect links and channel-bot connections: circular NyxID mark, "Authorize application" heading with the requesting app highlighted, plain-language permission rows, and a trust note above Allow/Decline. Client ID, redirect and raw scopes move under App details. The Low/Medium/High scope badges are removed; they were client-side labels, not server decisions. Service access shows each service's catalog description (two lines max) in a scrollable list with edge fades. Customize toggles a picker that closes via Done or Save selection. GET /user-services list responses now include catalog_service_description. Form fields posted to /oauth/authorize/decision are unchanged. Adds a dev-only /oauth-consent-preview route with sample data and disabled decisions. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * test(nyxbot): wait for relayed message instead of a fixed sleep the_same_question_is_not_worked_on_twice slept 300 ms after a Lark relay callback that returns 202 before recording the message. The instrumented coverage build on rollup PR #1700 took longer, so the reply target was not yet recorded. Poll the home thread (bounded to 10 s) until it is, keeping the assertions unchanged. Record the follow-up in the rollup notes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(rollup): record #1701 in the 2026-09-29 ctkm-1 rollup Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(auth): allow the code-free registration test 5 s under coverage The #1690 test 'allows email registration without a code when the flag is disabled' failed once in the rollup's frontend coverage run: the register call had not happened within waitFor's default 1 s. Use a 5 s timeout, as other slow frontend waits do, and record the follow-up in the rollup notes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(billing): keep historical usage priced after price removal (#1702) Re-authoring a service price deleted the retired Lago code's billing_rate_cache row, so every historical usage_meter row recorded under that code lost its only price and GET /billing/usage returned null costs; the Usage page then showed Unavailable for the service and for the Spend total. Grants were never the cause. - Price removal marks the rate row retired_at instead of deleting it; new reservations refuse retired rates, historical pricing keeps reading them, and a re-synced price clears the mark. - get_usage prices historical groups by grant-settled derivation, then the cached rate, then per-row reservation rates (exact Decimal128 credits, as exact settlement does), else null with grant credits still known. - The Usage page shows lower bounds (≥) with an unpriced-record count instead of Unavailable when only some records are unpriced. - Docs: glossary precedence, admin usage limitation, rollout note. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * docs(rollup): record #1702 in the 2026-09-29 ctkm-1 rollup Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * ci: build backend test binaries with line-table debuginfo Backend Test and Backend Billing Smoke died five times out of seven attempts on the 2026-09-29 rollup head with exit 143 ("The runner has received a shutdown signal") four to five minutes into compiling the nyxid test binary, before any test ran. The full-DWARF test binary exhausts the hosted runner's memory during codegen and linking. Both jobs now set CARGO_PROFILE_TEST_DEBUG=line-tables-only, which keeps panic locations and backtraces and changes nothing for local builds or the coverage jobs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(chat): open connector and channel setup in reusable overlays (#1707) * feat(chat): open connector and channel setup in reusable overlays * fix(chat): harden setup popup lifecycle and restore link focus * feat(channels): add tracked bot setup links and signed callbacks (#1705) * feat(channels): add tracked bot setup links and signed callbacks * fix(channels): preserve bot creation calls in production builds * fix(cli): save bot webhook signing secrets to private files * ci: bound backend coverage debug information * docs: record bot-link callbacks and rollup verification * fix(oauth): make Google Workspace grants optional (#1706) * fix(oauth): make Google Workspace grants optional Accept partial Google consent, remove seeded required-scope metadata across Workspace products, and show last reported grants in service details. * test(oauth): match optional Workspace seed wording * feat(oauth): show grants for every Google Workspace product * test(oauth): retain prior scope evidence when response omits scopes * ci: bound backend coverage debug info for hosted runners * docs: record Google OAuth grant fix in rollup --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
ctkm-aelf
added a commit
that referenced
this pull request
Sep 30, 2026
* rollup: 2026-09-29 ctkm-1 integration into main (#1700) * feat(auth): gate signup invitation codes behind default-on feature flag (#1690) Signup invitation codes are now an operator choice. The requirement is behind the global, default-on `auth:invitation-code` feature flag, which replaces the `INVITE_CODE_REQUIRED` environment variable and can be toggled in Admin > Feature Flags without a restart. - Enabled (default): email signup requires a valid code; browser social signup can redeem one; native social token exchange still rejects first-time signup. - Disabled: email and first-time social signup succeed without a code. - Flag is global only; scoped overrides are rejected. The backend resolves it on every signup attempt and /api/v1/public/config reports the effective state. - Invitation-code admin page, API and CLI are retained; the page states when codes are not required. Organization invitations are unchanged. - Rollout: deploy backend before frontend. Deployments with INVITE_CODE_REQUIRED=false must disable the flag to keep signup open. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(rollup): record 2026-09-29 ctkm-1 rollup Records #1690 (default-on auth:invitation-code signup gate), its reviewed head and squash commit, the main sync to e96a507, rollout notes and verification. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(oauth): redesign consent screen to match connection flows (#1701) Rework the OAuth consent page into the centered card used by connect links and channel-bot connections: circular NyxID mark, "Authorize application" heading with the requesting app highlighted, plain-language permission rows, and a trust note above Allow/Decline. Client ID, redirect and raw scopes move under App details. The Low/Medium/High scope badges are removed; they were client-side labels, not server decisions. Service access shows each service's catalog description (two lines max) in a scrollable list with edge fades. Customize toggles a picker that closes via Done or Save selection. GET /user-services list responses now include catalog_service_description. Form fields posted to /oauth/authorize/decision are unchanged. Adds a dev-only /oauth-consent-preview route with sample data and disabled decisions. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * test(nyxbot): wait for relayed message instead of a fixed sleep the_same_question_is_not_worked_on_twice slept 300 ms after a Lark relay callback that returns 202 before recording the message. The instrumented coverage build on rollup PR #1700 took longer, so the reply target was not yet recorded. Poll the home thread (bounded to 10 s) until it is, keeping the assertions unchanged. Record the follow-up in the rollup notes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(rollup): record #1701 in the 2026-09-29 ctkm-1 rollup Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(auth): allow the code-free registration test 5 s under coverage The #1690 test 'allows email registration without a code when the flag is disabled' failed once in the rollup's frontend coverage run: the register call had not happened within waitFor's default 1 s. Use a 5 s timeout, as other slow frontend waits do, and record the follow-up in the rollup notes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(billing): keep historical usage priced after price removal (#1702) Re-authoring a service price deleted the retired Lago code's billing_rate_cache row, so every historical usage_meter row recorded under that code lost its only price and GET /billing/usage returned null costs; the Usage page then showed Unavailable for the service and for the Spend total. Grants were never the cause. - Price removal marks the rate row retired_at instead of deleting it; new reservations refuse retired rates, historical pricing keeps reading them, and a re-synced price clears the mark. - get_usage prices historical groups by grant-settled derivation, then the cached rate, then per-row reservation rates (exact Decimal128 credits, as exact settlement does), else null with grant credits still known. - The Usage page shows lower bounds (≥) with an unpriced-record count instead of Unavailable when only some records are unpriced. - Docs: glossary precedence, admin usage limitation, rollout note. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * docs(rollup): record #1702 in the 2026-09-29 ctkm-1 rollup Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * ci: build backend test binaries with line-table debuginfo Backend Test and Backend Billing Smoke died five times out of seven attempts on the 2026-09-29 rollup head with exit 143 ("The runner has received a shutdown signal") four to five minutes into compiling the nyxid test binary, before any test ran. The full-DWARF test binary exhausts the hosted runner's memory during codegen and linking. Both jobs now set CARGO_PROFILE_TEST_DEBUG=line-tables-only, which keeps panic locations and backtraces and changes nothing for local builds or the coverage jobs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * feat(chat): open connector and channel setup in reusable overlays (#1707) * feat(chat): open connector and channel setup in reusable overlays * fix(chat): harden setup popup lifecycle and restore link focus * feat(channels): add tracked bot setup links and signed callbacks (#1705) * feat(channels): add tracked bot setup links and signed callbacks * fix(channels): preserve bot creation calls in production builds * fix(cli): save bot webhook signing secrets to private files * ci: bound backend coverage debug information * docs: record bot-link callbacks and rollup verification * fix(oauth): make Google Workspace grants optional (#1706) * fix(oauth): make Google Workspace grants optional Accept partial Google consent, remove seeded required-scope metadata across Workspace products, and show last reported grants in service details. * test(oauth): match optional Workspace seed wording * feat(oauth): show grants for every Google Workspace product * test(oauth): retain prior scope evidence when response omits scopes * ci: bound backend coverage debug info for hosted runners * docs: record Google OAuth grant fix in rollup --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * feat: NyxBot guests use specialists' services at owner-set levels; Telegram bot creators are owners; Lark groups answer only bot mentions (0.38.0) (#1712) * fix: a Telegram bot created through NyxID knows its owner: the creating account is verified on link or first message, and Start greets instead of refusing * fix: only a creator bound by the owner's own setup challenge is trusted, in private chats; link-time grants are audited and NyxBot keeps the verify link as a fallback * chore: bump version to 0.37.2 * fix: guests use a specialist's services except deleting; Lark groups count only mentions of the bot itself * fix: guests are refused calls that look like deleting by what they send, and never raise approvals; Lark bot ids cached per app * fix: guest delete checks cover GETs, body method overrides, unparsable JSON and code fields; guests never run on the owner's approval grants * feat: owners set what guests may do with each of a specialist's services (read, use, all), from the agent page or by asking NyxBot; destructive operations come from spec markers, not word lists * test: agent fixtures carry guest_access * fix: guest access judges every requested method, keeps levels beside grants for rolling deploys, honours read-only specs and catalog markers on mounted specs; Drive trash and content replace are destructive * fix: grants form builds its request without an unused binding * fix: guest calls never carry method overrides; Calendar event and Bitable record updates are destructive; a re-granted service starts at the default guest level * fix: guests' default use is reading, creating and acting (no PUT/PATCH/DELETE); Aevatar's destructive markers stay unchanged and NyxID marks POST edits itself; only stored catalog contracts widen reads; override keys read as PHP reads them * fix: NyxID's per-operation x-nyxid-changes-existing (true for POST edits, false for PUT actions); override checks follow the body's content type; hosted overlays mounted by URL are catalog contracts; all-level grants say they include deleting * fix: only a catalog contract may say an operation only acts; method fields count when they name another changing verb, in JSON bodies too; ; separates fields; hosted overlays share one check * fix: override checks skip empty, text and binary bodies; hosted overlay lookups share NyxID's compiled copy without cloning * chore: bump version to 0.38.0 --------- Co-authored-by: chrono-kw <chrono-kw@users.noreply.github.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: chronoai-kai <kaiweichronoai@gmail.com> Co-authored-by: chrono-kw <chrono-kw@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Squash-merged into
rollup-2026-09-29-ctkm-1asa29056ef8328ae3cfd5bcca51a352e1408163c04. The landed tree exactly matches validated sourced08d3d0c; stable patch IDs also match. Included in #1700.Summary
POST /api/v1/channel-connect-linksand the/connect/bot/{token}page cover manual, managed, and Telegram setup; Agent Keys can create/read/cancel links while completion requires an authorized human.--webhook-signing-secret-file: the secret is saved to a new file (mode0600on Unix), while terminal and JSON output contain only its path and key ID. Existing files and symlinks are rejected before creation; the HTTP API still returns the signing secret once. Rebuild the embedded CLI wizard because its telemetry source closure changed.Backend head/base coverage builds use
CARGO_PROFILE_TEST_DEBUG=line-tables-onlyto reduce compiler memory demand after repeat runner shutdowns during full-DWARF compilation. The tests, LLVM coverage instrumentation, and 73% backend line threshold remain unchanged; the contributor guide records the recurring-failure response.Connector compatibility
Existing production service Connector links retain their routes, request/response schemas, token behavior, event names, frontend flows, and webhook delivery behavior. The service-link helper change only exposes the existing app/callback validator within the crate. The existing developer-webhook entry point retains its original HTTP client, timestamp behavior, and quota; bot links explicitly opt into their separate delivery behavior and quota. Existing bot setup entry points retain their signatures and select the new link-aware behavior only when a link is supplied.
The bot-link contract and source map are documented in
docs/CHANNEL_BOT_RELAY.md;docs/API.mdcross-references the existing service-link API and the new bot-link API. Published web and CLI guides include creation examples, event payloads, signature verification, retries, and callback setup.Test Plan
cargo test -p nyxid-cli --test wizard_bundle_freshness.cargo fmt --all -- --checkandgit diff --checkpassed. CLI Clippy passed across all targets with-D warningsafter the secret-file change.012dd86f(feat(chat): open connector and channel setup in reusable overlays #1707). The shared bot-setup conflict preserves overlaystayInPlacebehavior and tracked-link result/one-time-secret retention. On combined source5147c6c4: 134 focused frontend tests, 25 Playwright browser cases, targeted ESLint, and the full production build pass. Existing Connector page, shared content, and hooks have no feature diff against the rollup.f00c203dbefore the overlay integration. The code-scanning API reports no open alerts for this PR.ce4414e6(fix: NyxBot specialists answer again and NyxBot can grant them services (0.37.1) #1703), rebuilt the wizard, and passed its Rust freshness test. Main was also merged into the rollup as3b80d68fto preserve ancestry. Merging final source into that rollup reproduces the source treed63cd0f6141262cde6737c89ec9ea3deeec398d7exactly.d08d3d0c: CI, CodeQL and Release passed. All 30 checks succeeded, four release checks intentionally skipped, none failed or remained pending. Backend nextest: 6,860 passed, two skipped; instrumented coverage run: 6,845 passed, two skipped, 87.40% lines against the unchanged 73% threshold. No open code-scanning alerts.Validation limit: manual onboarding against live external bot providers was not performed.
Checklist