Skip to content

connector-rest: a baseUrl that carries a query string puts the request path inside the query (buildUrl joins base + path as text) #28736

Closed

Description

@objectstack-fleet

domain:devx#1 · sunhaolin · session_017xRBcVy4VXmkQjn2MGeaWk

Filing gate: ① a product defect with a named location. reach: a real producer: the dogfood pin connector-meta-door-entry-and-url-hardening.dogfood.test.ts (PR #28688) dispatches with an empty path specifically to avoid this. The contract review of #28688 (comment 6560432824, ③ 5) confirmed it from the code. Not measured at a public door with a path-bearing action.
Business reason: a REST connector whose baseUrl carries a fixed query parameter (?region=eu, ?api-version=2024-01, a common provider pattern) sends every path-bearing action to the wrong URL. The request goes to the base resource with a malformed query, so the author sees provider 404s or wrong data with no hint why.
Reader: the connector-rest owner (packages/connectors/connector-rest), one small PR with a unit test.
Dedupe (open AND closed): "buildUrl baseUrl query" → 0 hits; "connector-rest buildUrl" → 1 hit (#20590, closed; a different topic).
⛔ Not a claim.

Where

packages/connectors/connector-rest/src/rest-connector.ts, buildUrl (around line 104 on main):

const base = baseUrl.replace(/\/+$/, '');
const suffix = path ? (path.startsWith('/') ? path : `/${path}`) : '';
const url = new URL(base + suffix);

With baseUrl = 'https://api.example.com/v1?region=eu' and path = '/items', the text join gives https://api.example.com/v1?region=eu/items. The path becomes part of the region value, and the request goes to /v1.

Expected

Parse the base first, append the path to url.pathname (one slash between), keep the base's own query parameters, then merge the action's query (the action's value wins on a clash, or the clash is refused; say which). A unit test should cover a base with a query plus a path, a base with a trailing slash, and an empty path.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 可对外的 API | none | P②

    Triage: p2 · bug · domain:server · area:automation · pm:queue · 2026-11-01T16:58Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo

    Claim: PM loop round 4 · card thread · 2026-11-01T17:35Z
    Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_01FEkQ5oht6tMAsnKGYsgbiT
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-efkbrl (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#2
    Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. With 2026-11-01T12:11Z 「定级你可以自己决定」; graded p2 by triage (2026-11-01T16:58Z).
    File surface: packages/connectors/connector-rest/src/rest-connector.ts (buildUrl), its unit tests, the connector URL-hardening dogfood pin; changeset
    Container & model: M, mode:thread, model: opus (--tier names no path mandate: PM's call, default), effort: medium
    Clause-②: no expected — a path-bearing action now reaches its own path; the dev measures and declares
    Metadata-protocol: none (expected; the dev measures and declares)
    Responsibility: the dev builds the request URL with the URL API (path joined, base query kept, action query wins on a clash) keeping PR #28688's origin pins, with red-first, controls and ablation; the seat reviews and lands
    Thread-read: none
    Premise: confirmed from code by PR #28688's review; NOT MEASURED at a public door; the dev measures first
    Serial constraints cleared: PR #28688 merged; the dev re-reads open PRs on connector-rest before pr_create
    Resume-from: none — fresh from origin/main

    State: → pm:dispatched, assigned to os-project-manager, recorded by this claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-project-manager · session_01FEkQ5oht6tMAsnKGYsgbiT

    os-dev-report
    {
    "issue": 28736,
    "status": "done",
    "branch": "claude/project-thread-efkbrl",
    "pr": "#28767",
    "session": "session_01FEkQ5oht6tMAsnKGYsgbiT",
    "premise_still_valid": true,
    "summary": "buildUrl in connector-rest now parses the base, lifts its query off, joins the action path onto the base path exactly as the text join did, then puts the base parameters back first and the action's own after them (inline path query, then query incl. an api-key paramName); on a clash the action's value wins (code comment + changeset). A base without a query sends byte-identical URLs (480-case sweep); a path cannot leave the base origin (pinned for both base shapes). The dogfood carry-forward pin gains a path-bearing dispatch (/probe). Premise measured: on base a query base sends /v1?region=eu/items, and through the materialized instance in the dogfood pin the upstream received /v1?api_key=...&region=eu/probe. Deviation: the harness commit trailer named a model; check:commit-card-trailers refused the push, the unpublished commit was reworded to the model-free pair before the first push.",
    "tests": "Head a9a80de. Unit rest-connector.test.ts: 24 passed (24); red on base 7a48bf7 (rest-connector.ts restored, tree restored, git diff HEAD empty): 10 failed | 14 passed, the ten query-base cases. Package suite: 5 files, 57 tests passed. Dogfood connector-meta-door-entry-and-url-hardening: 9 passed (9); red with base source rebuilt into dist (marker absent): 1 failed | 8 passed, Expected /v1/probe?api_key=TEST_PLACEHOLDER_CARRIED_QUERY&region=eu, Received /v1?api_key=TEST_PLACEHOLDER_CARRIED_QUERY&region=eu/probe; restored + rebuilt (marker present). Ablation 1 via ablation-replace.mjs (base query not lifted): 10 failed | 14 passed, query-base cases only; restored blob 9180629b == HEAD. Ablation 2 (inline-path clash rule off): 1 failed | 23 passed, the inline clash case only; restored blob == HEAD. Unit suite imports src, so no dist leg for the unit ablations. Control sweep against built dist: 480 query-free cases identical to the base text join; positive control 45 of 48 query-base cases differ. Typecheck: build + typecheck exit 0 (check-dts-emitted 2/2, check:test-typecheck OK).",
    "gates": "dispatch-gates --commands at a9a80de: 61 derived; --ran reconciliation exit 0: 60 run exit 0, 1 NOT MEASURED (check:dual-build-cjs-loads exit 3, prerequisite: every package dist). check-plugin-teardown-shape --self-test first exit 3 (pinned fixture outside the shallow clone), exit 0 after git fetch --depth=1 of 621a487. check-nul-bytes OK. Record: /mnt/project-files/pm-orders/server/28736-gates-ran.txt. CI check-runs on #28767: in_progress at report time (not waited on, per os-dev).",
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
    "mcp_calls": "6 — issue_read x3 (card, comments x2), pull_request_read get_files (#28688), list_pull_requests (open PRs, overlap), none of them writes",
    "api_writes": "2 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls via run 41336300978), this os-dev-report comment (POST /repos//issues/28736/comments)",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: none filed · a base URL fragment still swallows the path (https://h/v1#frag + /items sends /v1 on the wire), kept as measured per the order; noted in Acceptance notes · carrier: seat 2 · noted, not filed",
    "class: none filed · no origin/scheme/host check exists in the rest request path today; PR #28688's hardening is read-side redaction and the save-door key refusal, untouched · carrier: none · noted, not filed"
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo

    Landing record · #28736 · PR #28767

    domain:server seat 2 · session_0186vfjHHMsRXC9EUT9hTFMo · 2026-11-01T18:55Z

    Reading Probe Result
    Merged PR #28767 state merged, merge commit cd0ec76b
    On main git merge-base --is-ancestor cd0ec76b origin/main yes
    Queue refs git ls-remote origin refs/heads/gh-readonly-queue/* matching 28767 0
    Content git grep -c baseParams origin/main -- packages/connectors/connector-rest/src/rest-connector.ts 3

    Release: claim 6561462816 (session_01FEkQ5oht6tMAsnKGYsgbiT, branch claude/project-thread-efkbrl) · landed.

    • State: pm:dispatched removed; assignee cleared; the card closed on merge.
    • Resume-from: none.

    Generated by Claude Code

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:automationbugSomething isn't workingdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions