Skip to content

Add field clearing to todos update - #370

Merged
jeremy merged 8 commits into
mainfrom
delightful-hamburger
Mar 25, 2026
Merged

Add field clearing to todos update#370
jeremy merged 8 commits into
mainfrom
delightful-hamburger

Conversation

@jeremy

@jeremy jeremy commented Mar 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Adds --no-due, --no-starts-on, --no-description flags to basecamp todos update for clearing fields
  • Also supports empty-value clearing: --due "", --starts-on "", --description ""
  • Detects conflicting usage (--no-due + --due "friday") and returns a clear error
  • Clears fields using BC3 API omission semantics: the PUT body includes all fields to preserve, omitting those to clear. Clearing due also clears starts (Basecamp enforces starts <= due).
  • Guards against nil Bucket in the clearing path

Test plan

  • basecamp todos update <id> --no-due clears the due date
  • basecamp todos update <id> --due "" also clears
  • basecamp todos update <id> --no-due --title "New" clears date + sets title in one call
  • basecamp todos update <id> --no-due --due "friday" returns usage error
  • basecamp todos update --help shows the clearing flags
  • Normal update path (--due "friday", --title "x") is unchanged

CI note

TestSurfaceSnapshot failure is pre-existing on main — the unit snapshot baseline has accumulated stale ARG removals unrelated to this PR. The merge-gating "CLI Surface Check" job (which runs check-cli-surface.sh separately) passes green.

Closes #293

Copilot AI review requested due to automatic review settings March 24, 2026 19:23
@github-actions github-actions Bot added commands CLI command implementations enhancement New feature or request labels Mar 24, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 1 file

Copilot AI 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.

Pull request overview

This PR extends basecamp todos update to support clearing nullable todo fields (due date, start date, description) via dedicated --no-* flags and by treating explicitly empty flag values (e.g. --due "") as “clear”.

Changes:

  • Add --no-due, --no-starts-on, --no-description flags and document clearing examples in help text.
  • Detect and error on conflicting clear/set usage (e.g. --no-due with a non-empty --due).
  • When clearing is requested, bypass the SDK typed request and issue a raw PUT with null values.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/commands/todos.go
Comment thread internal/commands/todos.go
@github-actions github-actions Bot added the tests Tests (unit and e2e) label Mar 24, 2026

@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: b8e9523169

ℹ️ 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".

Comment thread internal/commands/todos.go
Copilot AI review requested due to automatic review settings March 24, 2026 20:06
@jeremy
jeremy force-pushed the delightful-hamburger branch from 8325fdb to e5d3707 Compare March 24, 2026 20:09

Copilot AI 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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/commands/todos_test.go
Comment thread internal/commands/todos_test.go
Comment thread internal/commands/todos.go
Comment thread internal/commands/todos.go
Comment thread internal/commands/todos_test.go
Comment thread internal/commands/todos_test.go
Comment thread internal/commands/todos_test.go

@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: 8325fdb7c6

ℹ️ 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".

Comment thread internal/commands/todos.go
Copilot AI review requested due to automatic review settings March 24, 2026 20:25

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="e2e/smoke/smoke_todos_write.bats">

<violation number="1" location="e2e/smoke/smoke_todos_write.bats:119">
P2: The new preservation smoke tests do not assert all fields they claim to preserve, so starts_on/content regressions can pass unnoticed.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread e2e/smoke/smoke_todos_write.bats Outdated

@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: 5ed8d807a6

ℹ️ 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".

Comment thread internal/commands/todos.go Outdated
@jeremy
jeremy force-pushed the delightful-hamburger branch from 5ed8d80 to 9637ea2 Compare March 24, 2026 20:30
@github-actions github-actions Bot added tui Terminal UI sdk SDK wrapper and provenance docs deps breaking Breaking change labels Mar 24, 2026
@github-actions

Copy link
Copy Markdown

⚠️ Potential breaking changes detected:

  • Change to the 'todos update' command introduces new mutually exclusive flag combinations (--no-due and --due, --no-description and --description, --no-starts-on and --starts-on), which may alter existing behavior for scripts or commands relying on previous flag handling.
  • Modification of the function signature for app.Account().Cards().Move to include an additional parameter (nil). This could affect any custom scripts or integrations relying on the API and not updated to handle the extra parameter.

Review carefully before merging. Consider a major version bump.

Copilot AI 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.

Pull request overview

Copilot reviewed 21 out of 22 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/commands/todos.go Outdated
Comment thread internal/commands/todos.go
Comment thread e2e/smoke/smoke_todos_write.bats Outdated
Comment thread e2e/smoke/smoke_todos_write.bats Outdated
@github-actions github-actions Bot removed the breaking Breaking change label Mar 24, 2026
Copilot AI review requested due to automatic review settings March 24, 2026 20:34

Copilot AI 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.

Pull request overview

Copilot reviewed 21 out of 22 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/commands/commands.go
Comment thread internal/commands/notifications.go
Comment thread internal/commands/notifications.go Outdated
Comment thread internal/commands/accounts.go

@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: b67390e749

ℹ️ 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".

Comment thread internal/commands/notifications.go Outdated
@jeremy
jeremy force-pushed the delightful-hamburger branch from b67390e to b824e1c Compare March 25, 2026 07:31
@github-actions github-actions Bot added the skills Agent skills label Mar 25, 2026

@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: b824e1c051

ℹ️ 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".

Comment thread internal/commands/schedule.go
Comment thread internal/commands/todos.go
Base automatically changed from sdk-0.7.0 to main March 25, 2026 07:37
jeremy added 7 commits March 25, 2026 00:38
…scription)

The SDK's UpdateTodoRequest uses omitempty on value types, making it
impossible to send JSON null to clear a field. When clearing is needed,
bypass the typed SDK path and issue a raw PUT with nil map values — the
same pattern the TUI uses in hub.go.

Supports both explicit flags (--no-due) and empty values (--due "").
Conflicting usage (--no-due --due "friday") returns a clear error.

Closes #293
Guard against nil Bucket in the clearing path. Add tests covering:
null emission for each --no-* flag, empty-value clearing (--due ""),
conflicting flag combinations, and combined clear+set operations.
The BC3 API clears fields by omission, not by sending null.
Rebuild the PUT body with all existing values preserved, omitting
only the fields being cleared. Clearing due also clears starts
(Basecamp enforces starts <= due).

Updates mock GET responses to include realistic todo data so
clear-path tests can verify field preservation.
Basecamp requires a due date when a start date is set, so clearing
the due while setting a start is contradictory. Return a clear usage
error instead of silently dropping the starts-on value.
Two new live-API smoke tests resolve the contract dispute between
the SDK typed-update path and the raw-PUT clearing path:

1. Update title only → verify due_on, starts_on, description survive
2. Clear due via --no-due → verify due/starts cleared, description preserved

Uses raw API GET to check null fields that the SDK omits via omitempty.
Move the clearDue+startsOn conflict check after clear detection so
--due "" --starts-on "value" is caught alongside --no-due --starts-on.
Add missing starts_on assertion to the field preservation smoke test.
Smoke tests: use todos update for --starts-on (create lacks it),
match description as HTML substring (API wraps in <p> tags).

Unit tests: add --starts-on "" and --description "" empty-value
clearing coverage alongside the existing --due "" test.
Copilot AI review requested due to automatic review settings March 25, 2026 07:39
@jeremy
jeremy force-pushed the delightful-hamburger branch from b824e1c to e397f06 Compare March 25, 2026 07:39
@github-actions github-actions Bot removed tui Terminal UI sdk SDK wrapper and provenance skills Agent skills docs deps labels Mar 25, 2026

Copilot AI 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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@jeremy
jeremy merged commit e48eadd into main Mar 25, 2026
27 checks passed
@jeremy
jeremy deleted the delightful-hamburger branch March 25, 2026 07:53
jeremy added a commit that referenced this pull request Jul 28, 2026
BC5 device logins as basecamp-cli (a trusted client) mint MULTI-ACCOUNT
refresh tokens: the token response carries an RFC 8707 resource
indicator (urn:bc:account:<id>), and bc3's refresh grant rejects a
multi-account refresh without that echo (400 invalid_request, per
Oauth::RefreshToken#resolve_target_account!). Without this, every device
login died at its first token expiry.

Credentials (internal/auth + the mirrored internal/sdk store) gain a
resource field; device login persists token.Resource; refresh echoes the
stored value on the form (sent only when set) and preserves it when the
refresh response omits it, so rotated credentials keep the binding. An
end-to-end test drives login → stored resource → forced refresh → echo
on the form → binding surviving a resource-less rotation.

Pins the SDK at oauth-resource-indicator head e583c994 (basecamp-sdk#478,
which stacks on #376/#370 and carries the device flow + resource
support); absorbed its API drift since the old 7207f742 snapshot
(VerificationURIComplete and RegistrationEndpoint are now *string). The
pin moves to #478's merged SHA before this lands.
jeremy added a commit that referenced this pull request Jul 29, 2026
BC5 device logins as basecamp-cli (a trusted client) mint MULTI-ACCOUNT
refresh tokens: the token response carries an RFC 8707 resource
indicator (urn:bc:account:<id>), and bc3's refresh grant rejects a
multi-account refresh without that echo (400 invalid_request, per
Oauth::RefreshToken#resolve_target_account!). Without this, every device
login died at its first token expiry.

Credentials (internal/auth + the mirrored internal/sdk store) gain a
resource field; device login persists token.Resource; refresh echoes the
stored value on the form (sent only when set) and preserves it when the
refresh response omits it, so rotated credentials keep the binding. An
end-to-end test drives login → stored resource → forced refresh → echo
on the form → binding surviving a resource-less rotation.

Pins the SDK at oauth-resource-indicator head e583c994 (basecamp-sdk#478,
which stacks on #376/#370 and carries the device flow + resource
support); absorbed its API drift since the old 7207f742 snapshot
(VerificationURIComplete and RegistrationEndpoint are now *string). The
pin moves to #478's merged SHA before this lands.
jeremy added a commit that referenced this pull request Jul 29, 2026
The device-flow + transport-hardening + resource-indicator stack landed on
basecamp-sdk main (#370/#376/#478); this replaces the branch-head pseudo-
version pins with the mainline merge commit. All tests green.
jeremy added a commit that referenced this pull request Jul 29, 2026
…urce echo (#582)

* auth: adopt resource-first OAuth discovery and RFC 8628 device flow

Bump the SDK to the oauth-device-flow head (7207f742) and rework login
around it:

- Discovery is now resource-first (RFC 9728 -> RFC 8414) from the base
  URL's origin via DiscoverFromResource. Only the two soft pre-selection
  outcomes (resource_discovery_failed, no_as_advertised) fall back to
  Launchpad; once a BC5 issuer is selected every failure is loud and is
  never converted into a Launchpad attempt. The fallback warning is kept
  for resource_discovery_failed, so production behavior is unchanged
  while BC5 is dark.
- A selected BC5 issuer runs the device authorization grant as the
  pre-registered public client "basecamp-cli" (oauth_type "bc5", no
  client secret). The device display callback is the trust boundary for
  the server-controlled response: verification URIs are validated with
  the same policy as other OAuth browser URLs before launching, printed
  copies are sanitized of ANSI/OSC/control sequences, and malformed
  display data aborts polling via context cancellation.
- The Launchpad path is unchanged: authorization-code with loopback
  callback or remote paste flow, legacy token format.
- The DCR/PKCE development flow against BC3 is removed (client
  registration, client.json load/save, PKCE challenge). Stored legacy
  "bc3" credentials refresh to a clear re-authenticate error; auth
  status still displays them. A stale client.json is left on disk.
- resourceOrigin strictly reduces the base URL to an origin: the path
  is stripped, everything else (userinfo, query, fragment, bad scheme,
  out-of-range port) is rejected without echoing the raw URL.
- Flag copy is provider-neutral: --device-code and --scope now describe
  both paths truthfully.

Test configs that constructed SDK clients with an empty BaseURL now set
one: the bumped SDK refuses to attach credentials when the request
target cannot be same-origin with the base URL.

* auth: cover device flow, discovery fallbacks, and refresh behavior

Behavior tests for the resource-first discovery and device flow adopted
in the previous commit, against an httptest resource-server/AS pair with
an injectable device-poll sleep:

- Device happy path: bc5 credentials with token endpoint and scope,
  public client_id on both device and token forms, browser launched
  with the validated code-embedding URI, code and URI logged.
- Flag matrix at the auth layer: Remote and NoBrowser print without
  launching (even with an injected BrowserLauncher); the default
  launches.
- Display trust boundary: invalid verification_uri_complete falls back
  to the plain URI and is never launched or shown; both URIs invalid or
  a user code that sanitizes to empty aborts with an API-class error
  before any token poll; OSC/CSI/CRLF sequences are stripped from
  logged copies while the raw validated URL goes to the launcher;
  browser-launch failure logs and continues.
- Scope wiring: explicit scope reaches the device-authorization form,
  unset scope is omitted; effective scope is token scope, then the
  requested scope, then "read".
- Soft fallbacks: missing resource metadata warns and falls back to
  Launchpad; valid metadata with no non-Launchpad issuer falls back
  quietly.
- Hard failures never fall back: ambiguous issuers, AS metadata fetch
  failure, and issuer binding mismatch surface their sentinels with
  zero requests to a recording Launchpad server; a selected issuer
  without device capability surfaces DeviceFlowUnavailable.
- Poll outcomes: access_denied surfaces its reason; one
  authorization_pending cycle then success; parent-context cancellation
  mid-poll still matches errors.Is(err, context.Canceled).
- bc5 refresh sends client_id=basecamp-cli with no client_secret key in
  the standard grant_type=refresh_token format; legacy "bc3"
  credentials refresh to a re-authenticate error without any network
  request.
- A command-level regression test proves --device-code selects the
  remote paste-callback flow (observable on the Launchpad path, where
  remote and local modes differ).
- Poisoned discovery endpoints (userinfo forms) are rejected before any
  POST; resourceOrigin table tests cover the strict origin reduction —
  including bare-"?" ForceQuery forms — asserting the raw URL is never
  echoed in failures.

* docs: describe device-flow login and retire client.json references

README: login now describes the device flow (automatic when the server
supports it, Launchpad authorization-code otherwise), scope help notes
Launchpad ignores it, and the config tree drops client.json — a
leftover copy from the removed development registration flow is
documented as safe to delete.

SKILL.md: provider-neutral wording for --device-code and --scope,
matching the flag help.

* auth: harden device display boundary; cover profile --device-code mapping

- Trim the sanitized user code and displayed URI: a code that reduces to
  whitespace is as unusable as an empty one and must abort before polling,
  not be displayed and polled until expiry.
- Range-check ports (1-65535) centrally in isSecureEndpointURL —
  url.Parse accepts https://host:70000/ without complaint, and such a URL
  must never be dialed, displayed, or launched. One rule now covers the
  token, device-authorization, authorization, refresh, and verification-URL
  consumers; poisoned and out-of-range-port token/device endpoints are
  rejected with zero POSTs.
- Regression-test the profile create --device-code → Remote mapping (the
  auth login copy was covered; the duplicated profile copy was not).

* go: drop stale SDK pseudo-version go.sum entries left by restack

The rebase onto main auto-merged go.sum with both the old device-flow
snapshot pin (7207f742) and main's bb363c84 pin present. go mod tidy
keeps only the go.mod pin. The SDK will be re-pinned to the
resource-indicator branch head next; the build is red until then
because the device-flow API is not on SDK main yet.

* auth: persist and echo the RFC 8707 resource indicator across refreshes

BC5 device logins as basecamp-cli (a trusted client) mint MULTI-ACCOUNT
refresh tokens: the token response carries an RFC 8707 resource
indicator (urn:bc:account:<id>), and bc3's refresh grant rejects a
multi-account refresh without that echo (400 invalid_request, per
Oauth::RefreshToken#resolve_target_account!). Without this, every device
login died at its first token expiry.

Credentials (internal/auth + the mirrored internal/sdk store) gain a
resource field; device login persists token.Resource; refresh echoes the
stored value on the form (sent only when set) and preserves it when the
refresh response omits it, so rotated credentials keep the binding. An
end-to-end test drives login → stored resource → forced refresh → echo
on the form → binding surviving a resource-less rotation.

Pins the SDK at oauth-resource-indicator head e583c994 (basecamp-sdk#478,
which stacks on #376/#370 and carries the device flow + resource
support); absorbed its API drift since the old 7207f742 snapshot
(VerificationURIComplete and RegistrationEndpoint are now *string). The
pin moves to #478's merged SHA before this lands.

* auth: canonicalize the resource origin; restack onto keyring-probe main

resourceOrigin now lowercases the host (and the localhost carve-out
checks the lowered host) and strips explicit default ports, normalizing
leading zeros — the SDK binds the RFC 9728 protected-resource identifier
to this string code-point exact, so an equivalent spelling
(HTTPS://3.BasecampAPI.com, https://3.basecampapi.com:443) previously
mismatched the advertised identifier and silently soft-fell back to
Launchpad. IPv6 brackets are restored around the lowered hostname.

Also restacked onto main 31c4936, preserving #581's bounded headless
keyring probe alongside the credential resource field, and tidied the
go.sum lines the auto-merge duplicated.

* go: pin the SDK at oauth-resource-indicator 819c0b86

Carries the full review round: exact-200 device token acceptance,
hardened Retry-After parsing, FileTokenStore resource persistence, and
the AuthManager empty/non-string resource classification. Provenance
updated to match; the pin moves to basecamp-sdk#478's merged SHA before
this lands.

* go: pin the SDK at oauth-resource-indicator e9469832

The converged basecamp-sdk#478 head, carrying the full review tail since
819c0b86: exact-200 + 4xx-gated protocol errors, status-first terminal
classification, request timeouts clamped to the code lifetime and the
shared 3600s ceiling, ASCII-only zero-pad-tolerant Retry-After parsing,
cooperative-cancellation coverage around every request, FileTokenStore
resource persistence, empty-device-endpoint capability guard, truncated
error interpolation, and the AuthManager no-expiry refresh guard. The
pin moves to #478's merged SHA before landing.

* go: pin the SDK at oauth-resource-indicator 298ad8e4

Carries the corrective-cycle Go fixes since e9469832: presence-aware
refresh expires_in (omission clears the stale expiry, explicit
non-positive fails as api_error), the pollToken and post-authorization
cancellation re-checks, the empty-device-endpoint capability guard, the
no-expiry AccessToken guard, and truncated error interpolation. The pin
moves to basecamp-sdk#478's merged SHA before landing.

* go: pin the SDK at oauth-resource-indicator fd2ff934

Carries the final corrective round's Go changes: the refresh expires_in
lifetime ceiling (an absurd value overflowed into a negative ExpiresAt
read as never-expiring) atop the presence-aware omission/non-positive
handling, plus the cancellation re-checks. The pin moves to
basecamp-sdk#478's merged SHA before landing.

* go: pin the SDK at oauth-resource-indicator 5645f897

* go: pin the SDK at oauth-resource-indicator 9c4cc6d6

* go: pin the SDK at oauth-resource-indicator b63b12e9

* go: pin the SDK at oauth-resource-indicator e421ea9f

* go: pin the SDK at oauth-resource-indicator 329d2278

Also repairs the corrupted updated_at the previous pin wrote (a mis-sliced
pseudo-version segment produced a non-ISO timestamp); the timestamp now
comes from the pseudo-version's 14-digit datetime field.

* go: pin the SDK at oauth-resource-indicator e3e0ea5c

* go: pin the SDK at oauth-resource-indicator 0bdb14ac

* go: pin the SDK at oauth-resource-indicator 05cc9f78

* auth: match loopback hosts case-insensitively in isSecureEndpointURL

DNS hostnames are case-insensitive, and resourceOrigin already lowercases
before the same localhost check — but isSecureEndpointURL passed u.Host
straight into hostutil.IsLocalhost, so http://LocalHost:3001 was rejected
as insecure. Lowercase before matching; the non-loopback rejection is
unchanged. The test fails against the un-fixed code.

* docs: state the real Launchpad fallback boundary

The README promised a Launchpad fallback whenever device flow was
unavailable; discoverOAuth falls back only on the two soft pre-selection
outcomes — once a BC5 issuer is selected, failures surface loudly and are
never converted into a Launchpad attempt.

* go: pin the SDK at oauth-resource-indicator 59358c11

* auth: name every constraint in the endpoint-validation error

requireSecureOAuthEndpoint also rejects userinfo, hostless forms, and
out-of-range ports — the message only mentioned the scheme rule, which was
misleading for those failures.

* go: pin the SDK at oauth-resource-indicator c55e9f3a

* go: pin the SDK at oauth-resource-indicator ac79e227

* go: pin the SDK at oauth-resource-indicator 602f7247

* auth: build the authorization-info URL from the resource origin

resourceOrigin explicitly supports pathful BaseURLs, but
AuthorizationEndpoint appended /authorization.json to NormalizeBaseURL —
which only trims a trailing slash — yielding a misrouted
host/api/v1/authorization.json. Use the canonical origin. The pathful test
fails against the un-fixed code.

* go: pin the SDK at oauth-resource-indicator e6112812

* go: pin the SDK at oauth-resource-indicator 145c0010

* go: pin the SDK at oauth-resource-indicator 351266ea

* go: pin the SDK at oauth-resource-indicator 644129714

Absorbs the pre-request issuance anchoring for device login (a slow
authorization response now counts against the code lifetime) plus the
round's Python/Ruby/TS hardening upstream. No CLI-side code changes.

* go: pin the SDK at oauth-resource-indicator 02ea83bf4

Absorbs the SPEC §16 receipt-anchoring for device login (request-leg
latency no longer shrinks the code window) plus the round's transport
and exchange hardening upstream. No CLI-side code changes.

* go: pin the SDK at oauth-resource-indicator 4b524ed1d

Absorbs the exchange token_type contract (Bearer only when absent,
typed api fault on present-but-empty) and the oauth-token fixture
tightening upstream. No CLI-side code changes.

* go: pin the SDK at oauth-resource-indicator 916b4297b

Absorbs the duplicate-Retry-After rejection and the round's transport
and parse-fault hardening upstream. No CLI-side code changes.

* go: pin the SDK at oauth-resource-indicator 7e924c0df

Absorbs the validate-then-mutate refresh ordering and Retry-After
digit-bound parity upstream. No CLI-side code changes.

* go: pin the SDK at oauth-resource-indicator 1b3e9a037

Absorbs the shared Retry-After digit bound in the Go device poller.
No CLI-side code changes.

* go: pin the SDK at the merged OAuth stack (9480aa4c84b8)

The device-flow + transport-hardening + resource-indicator stack landed on
basecamp-sdk main (#370/#376/#478); this replaces the branch-head pseudo-
version pins with the mainline merge commit. All tests green.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands CLI command implementations enhancement New feature or request tests Tests (unit and e2e)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: basecamp todos update command

2 participants