Skip to content

OAUTH-001B10 — Require exact Strava disconnect client confirmation #610

Closed

Description

@daliu

Outcome

My Account may hide the connected Strava identity and activity only after the callable fulfills with one exact ordinary confirmation: { ok: true }. Every other fulfilled value must enter the existing fixed unknown-result path.

Parent: #88. This is the explicitly reserved OAUTH-001B10 child and does not close the parent.

Problem

On exact main 9d8bfaae0a4f9e573053b4035954e933ae626875, src/services/strava/stravaService.ts returns unchecked callable result.data. StravaSection treats every fulfillment—including { ok: false }, null, or malformed data—as confirmed, hides the connected athlete/activity, and shows Connect Strava. That can falsely acknowledge an external-account revocation that the client did not confirm.

Invariant and allowed transition

Only an exact ordinary response with the sole own enumerable data property ok equal to primitive true may resolve. The service returns a fresh frozen canonical { ok: true }.

Null, primitives, arrays, custom/null prototypes, missing or extra keys, symbol/non-enumerable keys, inherited confirmation, accessors, ok: false, non-Boolean values, and exceptional reflection/data access reject with exactly Invalid Strava disconnect response. without echoing the input. The existing component catch must then preserve the connected view, end the busy state, re-enable Disconnect, and show the fixed refresh-before-retry alert.

Transport rejection stays uninspected and preserves its rejection identity.

Browser JavaScript cannot reliably identify every faithfully transparent nonthrowing Proxy. Firebase wire decoding does not ordinarily produce Proxies or accessors. The boundary safely projects any exact presented data contract rather than retaining the received object; revoked or throwing reflection is contained by the fixed error. Do not overclaim Proxy detection.

Exact scope

  • src/services/strava/stravaService.ts: one exact disconnect-confirmation reader; callable response becomes unknown; narrow the successful return to a fresh frozen Readonly<{ ok: true }>.
  • src/pages/account/Account.test.tsx: a trustworthy RED, exact positive/negative/adversarial service matrix, transport-rejection preservation, and one composition proof through the existing fixed browser failure path.
  • SECURITY.md: only the RISK-024 current-truth hunk; record this source boundary and remove only the now-resolved client-confirmation residual.
  • docs/officers/EVENTS_SHOP_MEMBERS.md: only the existing “Strava disconnect failure privacy — SOURCE ONLY, NOT LIVE” procedure; distinguish rejected requests from fulfilled non-confirmations and preserve the no-terminal refresh/stop/escalate path.

No StravaSection.tsx runtime change is expected. Its existing rejection path already has the required fixed unknown-result behavior.

Excluded: Functions, Firestore/Rules, schemas/migrations, App Check/Auth admission, packages/locks, workflows, provider calls/configuration, real accounts/tokens/data, Firebase deployment, website publication, and live verification.

Acceptance and tests

  • Trustworthy RED on the exact base: a callable fulfillment { data: { ok: false } } must reject with the fixed response error; old source instead fulfills { ok: false }.
  • Accept only exact ordinary { ok: true }, including frozen input.
  • Return an independent, frozen canonical result and never the received object.
  • Reject missing, false, non-Boolean, extra, inherited, accessor-backed, malformed, exceptional, and hostile-reflection shapes without invoking response field getters or exposing detail.
  • Preserve transport rejection identity without inspection.
  • Compose the actual service validator with My Account and prove an invalid fulfillment keeps athlete/activity visible, keeps Connect hidden, re-enables Disconnect, shows only the fixed alert, and logs no raw detail.
  • Run focused frontend tests, the full frontend suite, lint baseline, SPA/safety checks, Functions/Rules/commerce regressions, diagnostic build, diff check, and dependency audits.
  • Independent runtime/security, test, and backup-officer review must return GO on the exact remote head.

No migration is required.

Officer and deployment boundary

Officer impact: Source will stop a fulfilled but unconfirmed disconnect result from hiding the connected view. The member still receives the existing instruction to refresh before another attempt.

Officer documentation: docs/officers/EVENTS_SHOP_MEMBERS.md, existing disconnect-failure procedure only.

Deployment evidence: At issue creation, none. Source, tests, merge, website publication, runmprc.com, Firebase deployment, Strava/provider state, production data, and live behavior must be recorded separately. No real disconnect or provider call is authorized.

Residual provider serialization/reconciliation, connection-only writers, durable audit/tombstone, IAM/encryption, protected deployment, configuration, and live proof remain under #88.

Activity

  1. self-assigned this
    on Aug 2, 2026
  2. added
    bugSomething isn't working
    priority:P0Launch blocker or urgent security risk
    type:securitySecurity or privacy boundary
    area:authAuthentication and authorization
    area:webWeb application and hosting
    size:SSmall focused issue
    status:in-progressClaimed and actively being implemented
    type:testingTest infrastructure and quality gates
    area:privacyPersonal data, consent, minimization, retention, and privacy operations
    on Aug 2, 2026
  3. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    CLAIMED by /root at 2026-08-02T07:09:52Z on branch codex/issue-610-strava-disconnect-confirmation, exact base 9d8bfaae0a4f9e573053b4035954e933ae626875.

    Exact ownership:

    • src/services/strava/stravaService.ts: exact fulfilled disconnect-confirmation reader and callable return boundary only.
    • src/pages/account/Account.test.tsx: separately named OAUTH-001B10 service matrix and one existing-browser-path composition test only.
    • SECURITY.md: RISK-024 current-truth hunk only.
    • docs/officers/EVENTS_SHOP_MEMBERS.md: existing Strava disconnect failure procedure hunk only.

    All other paths/hunks are excluded. StravaSection.tsx, Functions, Firestore/Rules, packages, workflows, provider/configuration, real accounts/tokens/data, deployments, and live behavior are unclaimed. Any overlap is a STOP-and-coordinate condition.

    Officer impact: source-only preservation of the connected view for a fulfilled non-confirmation.
    Officer documentation: docs/officers/EVENTS_SHOP_MEMBERS.md, exact existing procedure hunk.
    Deployment evidence: none at claim; no website, Firebase, Strava, production-data, or live action.

  4. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    TRUSTWORTHY RED on exact base 9d8bfaae0a4f9e573053b4035954e933ae626875, before runtime or documentation changes:

    • Test-only binary diff SHA-256: a306c6f36f0962feac599c6121184745164eaf67e04664a70d5544cc7fe5fc6f
    • Command: CI=true react-scripts test --watch=false --runInBand src/pages/account/Account.test.tsx -t OAUTH-001B10
    • Result: 1 intended failure, 152 unrelated tests skipped.
    • Old source fulfilled { ok: false }; the regression requires the fixed Invalid Strava disconnect response. rejection.
    • The callable was invoked once with the exact empty ordinary request.

    Only the named test exists at this marker. No runtime, SECURITY/officer documentation, Firebase, Strava/provider, data, deployment, or live change has been made. Claim remains held.

  5. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    RED EVIDENCE CORRECTION: the exact test-only binary diff SHA-256 is 03e16813248431f9a3f33cf8a6d0a642406ab5f13419ab9f762b05de56e2794a. The prior comment’s hash was a transcription error; its exact base, command, one intended failure, skipped count, observed old-source fulfillment, and no-runtime/no-doc boundary remain correct.

  6. removed their assignment
    on Aug 2, 2026
  7. daliu commented on Aug 2, 2026

    @daliu
    ContributorAuthor

    COMPLETE / CLOSED / CLAIM RELEASED

    OAUTH-001B10 is complete. PR #611 merged after exact-head self-review and three independent GO reviews.

    Evidence:

    • Base: 9d8bfaae0a4f9e573053b4035954e933ae626875
    • Reviewed head: 4ea0b7f0e1d830f42a5c33c6d4cfed3b5f35c56d
    • Reviewed diff SHA-256: 5975d21f867b27fafab901a10f5aa84e99c063f62c94be8c182c32405225566d
    • Merge/main: 63d29bedf379a857421501a5c0938c2901618095
    • Reviewed-head and merge tree: a4c23c8b69a6076f01c3f4be3f06efed50fa9a72
    • PR CI 30737652078: all five required jobs passed.
    • Post-main CI 30737752006: all five required jobs passed.
    • Focused service/UI tests: 37/37; full Account tests: 188/188; frontend: 987/987; Functions: 7,524 passed with 64 intentional skips; Rules: 418/418; commerce journal: 63/63; SPA navigation: 11/11; production diagnostic build passed.
    • Security review covered exact confirmation shape, inherited/accessor/symbol/Proxy cases, transport-error identity, logging, data retention, authorization, App Check, idempotency, and migration impact.

    Officer impact: A disconnect success is now accepted only after the callable returns the exact documented {ok: true} confirmation. Malformed fulfilled responses stay on the connected screen and show the fixed failure path.

    Officer documentation: docs/officers/EVENTS_SHOP_MEMBERS.md; engineering risk record: SECURITY.md RISK-024.

    Deployment evidence (checked 2026-08-02):

    • Source changed: yes.
    • Tests passed: yes, including post-main CI.
    • Code merged: yes, exact main above.
    • Website published: no. Netlify preview deploy 6a6eeffad8ef7f0008e9bfc9 is ready but published_at is null. Main attempt 6a6ef0b0b8a874000896f33a is error with published_at null.
    • runmprc.com verified: the public release marker still identifies WEB-002A — Publish bounded Shop and Events permissions containment #473 (controlCommit 9ad6837756cdd409d296009fde5082eeeae5c059, source 39ab8649df411262c8109a3c81a57bc38f1e168b), not this merge.
    • Firebase deployed: no evidence; GitHub deployments for the exact merge are empty.
    • Outside provider configured: no change and not claimed.
    • Production behavior verified: no; this client containment is merged and tested but not evidenced live.
    • Production data/checkout/payment behavior: unchanged and not exercised.

    Residual: JavaScript reflection can encounter exotic provider-created Proxy objects; throwing/revoked proxies fail closed, and a transparent proxy that presents the exact contract is projected into a new frozen local object. The callable backend remains the trusted source of disconnect state. No schema, migration, package, live provider, or production-data change was required.

    The issue is closed as completed, the branch is deleted remotely, the assignee and in-progress label are removed, and the claim is released.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:authAuthentication and authorizationarea:privacyPersonal data, consent, minimization, retention, and privacy operationsarea:stravaStrava integrationarea:webWeb application and hostingbugSomething isn't workingpriority:P0Launch blocker or urgent security risksize:SSmall focused issuetype:reliabilityReliability and recoverytype:securitySecurity or privacy boundarytype:testingTest infrastructure and quality gates

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions