Skip to content

fix(cli): close follow-up gaps - #7137

Merged
waleedlatif1 merged 5 commits into
stagingfrom
fix/post-merge-followups
Aug 27, 2026
Merged

fix(cli): close follow-up gaps#7137
waleedlatif1 merged 5 commits into
stagingfrom
fix/post-merge-followups

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Summary

Follow-ups found by black-box testing the shipped CLI after #7126, plus two pre-existing repo issues found alongside them. Every item was reproduced against the real binary before being changed; two reported issues turned out to be false positives and were left alone.

Refusals that didn't fire

  • sim profiles <anything> exited 0, so a probe reading the exit code to ask whether a command exists was told yes. It was the one group the earlier guard missed — exempted alongside files restore, but only that one takes an operand. Registering its listing as a default subcommand puts profiles back among the pure dispatchers the existing guard already covers, so the guard itself didn't need widening.
  • A blank numeric value in a request body still became a real 0 — the same coercion already fixed for query strings, where the guard keyed off the slot when the real distinction is the field's declared type. 21 fields across 15 operations were affected, including required ones. An empty body string still clears a description.
  • Blank values for --endpoint, --workspace and --profile fell back to what was configured instead of being refused, and a whitespace-only workspace was accepted verbatim.

Help that contradicted itself

  • Three commands refuse a workspace API key and said nothing while their menu siblings said so — in sim secrets --help, list and delete carried the warning and set didn't, reading as though set accepts one. They're hand-written, so they never reached the code that appends it. The note now comes from a helper taking the operation, so a command names the operation it invokes and the two can't disagree, and a test fails if a hand-written command ever calls a restricted operation without it. 56 → 60 rendered commands.
  • Two schema descriptions named request fields no flag spells (folderPaths, sortBy=startedAt). Rewritten to name the concept, since these strings serve both the REST reference and CLI help. Mentions that are a plain kebab transform (includeOutput--include-output) were deliberately left.

Smaller correctness

  • A hand-written profile name carrying padding listed as reachable but resolved to defaults instead of erroring — silent, and the wrong direction.
  • A rejected value was echoed unredacted by four messages while their siblings redacted it. No escape injection was possible (ANSI was already stripped); the leak was bare newlines.
  • A write now re-emits a section header it wasn't asked to touch byte for byte. The blank-line normalisation around it is left alone — making the writer position-faithful is a change to its model, not a fix, and belongs in its own PR.

Pre-existing, found in passing

  • One of the eight script tests was reachable from no entrypoint, so it had never run in CI. It passes; it was simply never invoked. This is the second time that hand-maintained list has drifted — the audit runner's own header records the first. The guard is a check:* script rather than a test, because the runner derives its list from that namespace and picks the guard up by name; a test would have had to be hand-added to the very list it guards.
  • A published spec sat outside the generator's manifest, and so outside its drift check, carrying six example ids with the texture of real generated ones. The new check globs the directory instead of reading the manifest, since the manifest is what omitted the file — it now covers 8 specs where the existing check covers 7.

Type of Change

  • Bug fix

Testing

Every fix reproduced against the real binary first, then proven red before green by hand-reverting the source and watching the test fail.

  • packages/sim-cli: 758 passing
  • apps/sim contract and v2 route suites: 1,892 passing
  • bun run lint, bun run check:audits (now 35 — both new guards register themselves), bun run test (full chain), both type-checks, all three generator --checks: pass

Not changed, deliberately

  • Two reported ids were false positives: one scored identically to its hand-authored neighbours under an objective pandigital test, so it was left alone rather than churned.
  • Client-side range and integer checks on numeric body fields: the blank case is the client fabricating a value the caller never typed; 1.5 reaches the wire verbatim and the server rejects it with its own message. The field spec carries no bounds, so any would have to be invented.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

…al-looking ids

One of the eight script tests was reachable from no entrypoint, so it had
never run in CI — it passes, it was simply never invoked. This is the second
time that hand-maintained list has drifted from the files beside it; the
audit runner's own header records the first. The guard against a third is a
`check:*` script rather than a test, because the runner derives its list
from that namespace and so picks the guard up by name — a test would have
had to be hand-added to the very list it guards.

A published spec sat outside the generator's manifest and so outside its
drift check, and carried six example ids with the texture of real generated
ones rather than the pandigital placeholders the rest of the repo uses. The
new check globs the directory instead of reading the manifest, since the
manifest is what omitted the file. The one pre-existing borderline id is
allowlisted with a reason: loosening the threshold to admit it would have
hidden one of the six.
`sim profiles <anything>` still exited 0, so a probe reading the exit code
to ask whether a command exists was told yes — the one group the earlier
guard missed. The exemption was written for commands that are both a group
and a leaf, but only `files restore` takes an operand; `profiles` takes
none. Registering its listing as a default subcommand puts it back among
the pure dispatchers the existing guard already covers, so the guard itself
did not need widening.

Three commands refuse a workspace API key and said nothing, while their
menu siblings said so — reading as though they accept one. They are
hand-written, so they never reached the code that appends the note. That
note now comes from a helper taking the operation, so a command names the
operation it invokes and the two cannot disagree, and a test fails if a
hand-written command ever calls a restricted operation without it.

A blank numeric value in a request body still became a real zero, the same
coercion already fixed for query strings: the guard keyed off the slot when
the distinction is the field's declared type. Twenty-one fields across
fifteen operations were affected. An empty body string still clears a
description.

Blank values for the root endpoint, workspace and profile flags fell back
to what was configured instead of being refused, and a whitespace workspace
was accepted verbatim. A hand-written profile name carrying padding listed
as reachable but resolved to defaults rather than erroring. Two schema
descriptions named request fields that no flag spells, and a rejected value
was echoed unredacted by four messages while their siblings redacted it.

A write now re-emits a section header it was not asked to touch byte for
byte. The blank-line normalisation around it is left alone: making the
writer position-faithful is a change to its model, not a fix.
@waleedlatif1
waleedlatif1 requested a review from a team as a code owner August 26, 2026 23:45
@vercel

vercel Bot commented Aug 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview Aug 27, 2026 12:53am

Request Review

@waleedlatif1 waleedlatif1 changed the title fix(cli): close follow-up gaps found by black-box testing the shipped CLI fix(cli): close follow-up gaps Aug 26, 2026
@greptile-apps

greptile-apps Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR closes several CLI correctness and documentation gaps, and the follow-up change completes the prior uppercase-UUID audit fix.

  • Rejects invalid command operands, blank profile overrides, and blank numeric body values.
  • Aligns restricted-operation help text across generated and hand-written commands.
  • Preserves unrelated INI section headers and sanitizes terminal-facing values.
  • Adds CI coverage for script tests and published OpenAPI example identifiers.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
scripts/check-spec-example-ids.ts Matches UUIDs case-insensitively and normalizes every spelling before checking the approved and sentinel sets, fully resolving the prior thread.
packages/sim-cli/src/runtime/request.ts Corrects blank body-field coercion while preserving intentional empty-string behavior for string fields.
packages/sim-cli/src/commands/auth.ts Tightens profile command dispatch, override-error handling, and terminal-safe presentation.
packages/sim-cli/src/config/profile.ts Strengthens validation for blank endpoint, workspace, and profile overrides.
packages/sim-cli/src/runtime/build.ts Centralizes restricted-operation help descriptions for generated and hand-written commands.
scripts/check-script-test-coverage.ts Adds an audit ensuring repository script tests remain reachable from the root test entrypoint.

Reviews (4): Last reviewed commit: "fix(scripts): match the uuid sentinels e..." | Re-trigger Greptile

Comment thread scripts/check-spec-example-ids.ts Outdated
The pattern only recognised lowercase hex, so an uppercase id in a
published spec was never examined and the audit reported success without
having looked at it.

Matching case-insensitively is not enough on its own: hex is
case-insensitive, so a mixed-case id counts `A` and `a` as two digits and
reports twenty distinct ones rather than sixteen. That inflated count
clears the threshold the texture test uses to recognise a hand-authored
placeholder, so a real id could have passed for one. The allowlist is an
exact-string lookup and would likewise have missed an uppercase spelling of
an entry. Both checks and the lookup now take a normalised id, while the
finding still reports the spelling as it appears in the file.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

/cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 26, 2026

Copy link
Copy Markdown

/cubic review

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai 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.

2 issues found across 29 files

Confidence score: 3/5

  • packages/sim-cli/src/commands/auth.ts rejects sim profiles help and sim profiles help --help as unknown commands, causing an expected help flow to exit with an error; include help in the known-command handling.
  • packages/sim-cli/src/config/profile.ts allows blank --profile, --endpoint, or --workspace values to be reported as success because profileListingContext swallows the guard error; preserve and rethrow override-validation errors so invalid input fails visibly.
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="packages/sim-cli/src/commands/auth.ts">

<violation number="1" location="packages/sim-cli/src/commands/auth.ts:774">
P2: When users invoke `sim profiles help` or `sim profiles help --help`, this hook treats Commander’s implicit `help` command as unknown and exits with an error. Include `help` in `known`, as `refuseHelpAfterUnknownCommand` does, so nested help remains reachable.</violation>
</file>

<file name="packages/sim-cli/src/config/profile.ts">

<violation number="1" location="packages/sim-cli/src/config/profile.ts:457">
P2: When `profiles` receives a blank `--profile`, `--endpoint`, or `--workspace`, this guard throws, but `profileListingContext` swallows the error and exits successfully after listing profiles. Preserve and rethrow override-validation errors before the broken-profile fallback.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/sim-cli/src/commands/auth.ts
Comment thread packages/sim-cli/src/config/profile.ts
Comment thread packages/sim-cli/src/config/profile.ts Outdated
Comment thread scripts/check-spec-example-ids.ts Outdated
A blank root flag was refused everywhere except `profiles`, where the catch
that lets a broken profile still list absorbed it and the command exited 0
after printing the table. The refusal now carries its own error class, which
is what the listing rethrows on — the two are distinguished by type rather
than by matching message text, and a genuinely broken profile still lists.

The unknown-profile message redacted the name the caller typed but not the
suggestion or the list of configured names beside it, which come from the
same file and are equally attacker-influenced once it has been hand-edited.
Those are redacted now, as is every other message in these two files that
quotes a name read out of the config, and the profile listing flattens the
names it renders the way it already flattened the error column.

The example-id audit judged a uuid by its digit texture, on the premise that
a real one essentially never looks hand-authored. Measured against ten
million generated ids, 0.81% of them do — one in 124, where this change
alone replaced six. Requiring each digit exactly twice takes that to zero
but rejects all fourteen placeholders now in the specs, so it is no cheaper
than the alternative. The audit now holds the eighteen ids the specs
actually use, which is one file rather than the twenty-seven a reserved
format would touch, and a new id fails until someone lists it — which is the
review the check exists to force.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

/cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 27, 2026

Copy link
Copy Markdown

/cubic review

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 30 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread scripts/check-spec-example-ids.ts Outdated
Accepting any id built from at most two distinct hex digits let something
through that was never on the approved list. A generated id essentially
never has that shape, so the practical risk was small — but this check had
just stopped being a shape test and become a list, and a structural
exception is the one thing that undoes that. The two ids it exists for are
the nil and max sentinels, and both are matched by value now.
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

/cubic review

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 27, 2026

Copy link
Copy Markdown

/cubic review

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 30 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Re-trigger cubic

@waleedlatif1
waleedlatif1 merged commit 6bbabbb into staging Aug 27, 2026
29 of 30 checks passed
@waleedlatif1
waleedlatif1 deleted the fix/post-merge-followups branch August 27, 2026 00:53
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.

1 participant