Skip to content

fix: preserve default scope for template operations#187

Draft
cursor[bot] wants to merge 2 commits into
mainfrom
cursor/critical-bug-inspection-d864
Draft

fix: preserve default scope for template operations#187
cursor[bot] wants to merge 2 commits into
mainfrom
cursor/critical-bug-inspection-d864

Conversation

@cursor
Copy link
Copy Markdown
Contributor

@cursor cursor Bot commented May 13, 2026

Description

Fixes a critical template CRUD scoping regression from the recent multi-scope template change. When users had HARNESS_ORG/HARNESS_PROJECT configured but omitted explicit template scope params, template create/delete/list/get calls stopped inheriting the configured project scope and could route to account scope instead. This could cause wrong-scope writes/deletes for common MCP usage.

The fix adds opt-in default scoping for multi-scope resources and enables it for templates: omitted scope fields use configured org/project defaults, while explicit scope: "account", scope: "org", scope: "project", global=true, or explicit org/project inputs remain supported.

Type of Change

  • Bug fix
  • New feature
  • Refactor
  • Documentation
  • Other

Checklist

  • Tests pass
  • Typecheck passes

Validation:

  • pnpm test tests/registry/registry.test.ts (86 tests passed)
  • pnpm typecheck
  • pnpm test (53 files, 1274 tests passed)
  • pnpm build
  • HARNESS_API_KEY=pat.test-account.token.secret HARNESS_ACCOUNT_ID=test-account HARNESS_TOOLSETS=templates timeout 3s node build/index.js stdio (startup succeeded; command exits 124 due expected timeout)
Open in Web View Automation 

Co-authored-by: Rohan Gupta <thisrohangupta@users.noreply.github.com>
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Co-authored-by: Rohan Gupta <thisrohangupta@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Found 3 issues against Sunil's architecture standards.

  1. The new account-scope validation does not protect the public harness_get(..., params: { global: true }) path, so a caller can still send mixed global + org scope.
  2. scopeOptionalDefaultFromConfig still forwards an implicit project-scoped template request with only project_id when no org can be resolved, instead of failing locally.
  3. The new multi-scope template behavior is not reflected in harness_describe, so the agent-facing contract is now behind the runtime behavior.

Assumptions:

  • I am treating Sunil's standards as requiring fail-loud scope validation and metadata/runtime parity for agent-discoverable behavior.

Verification:

  • pnpm build
  • pnpm typecheck
  • pnpm test -- tests/registry/registry.test.ts -t template (local run passed; Vitest reported 53 files / 1276 tests)
  • Reproduced the two scope gaps with small built-node probes on 180e6cfa1dce1823c45a07b21e5fc1ea8d008b3e before posting this review.
Open in Web View Automation 

Sent by Cursor Automation: Sunil On Demand Architecture Review

accountIdentifier: "__GLOBAL_TEMPLATES_ACCOUNT_ID__",
versionLabel: "1.0.8",
});
expect(call.params).not.toHaveProperty("orgIdentifier");
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This only exercises the internal account_id path. The public harness_get flow still rewrites params.global=true into account_id after dropping global, so dispatch never sees the account-scope signal and will happily keep an explicit or URL-derived org_id.

I reproduced that on the built branch with harness_get({ resource_type: "template", resource_id: "helmDeployAction", org_id: "default", params: { global: true, version_label: "1.0.8" } }), and the request params came out as:

{
  "accountIdentifier": "__GLOBAL_TEMPLATES_ACCOUNT_ID__",
  "orgIdentifier": "default",
  "versionLabel": "1.0.8"
}

Please add coverage through the shared tool path or preserve a scope marker so the new validation actually protects the user-facing API.

Comment thread src/registry/index.ts
if (input.org_id) {
params[orgParam] = input.org_id as string;
}
if (input.project_id) {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There is still a fail-loud gap on the implicit project-scope path. When scopeOptionalDefaultFromConfig is enabled and the caller provides project_id but no org_id, this branch only backfills the org when HARNESS_ORG is set. If it is unset, we still fall through and forward a partial request.

I reproduced registry.dispatch(client, "template", "delete", { template_id: "deploy_step", version_label: "v2", project_id: "proj-only" }) with HARNESS_ORG unset, and the request params were just:

{ "projectIdentifier": "proj-only" }

Since the explicit scope: "project" branch already rejects missing orgs, this implicit path should fail the same way instead of punting a malformed scope to the backend.

{ name: "search_term", description: "Filter templates by name or keyword" },
{ name: "template_type", description: "Template entity type", enum: ["Pipeline", "Stage", "Step", "CustomDeployment", "MonitoredService", "SecretManager", "ArtifactSource"] },
{ name: "template_list_type", description: "Template list type", enum: ["Stable", "LastUpdated", "All"] },
{ name: "scope", description: "Template scope. Omit to use configured org/project defaults; use account or org to target those scopes explicitly.", enum: ["account", "org", "project"] },
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Adding scope only to listFilterFields does not fully expose the behavior this PR introduces. With scopeOptionalDefaultFromConfig enabled, templates now support account/org/project semantics for write flows too, but harness_describe(resource_type="template") still reports only scope: "project", and the create/update/delete metadata exposes no structured scope input.

That leaves the new account/org write paths effectively undiscoverable to agents, which is a contract mismatch under the repo guidance to put agent-facing behavior in structured metadata rather than runtime-only flags or prose. Please surface the supported scopes / write-time selector in the describe output as well.

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.

2 participants