Skip to content

feat(config): read ~/.testsprite/config for persistent defaults (endpoint_url, output, project_id)#225

Open
Andy00L wants to merge 3 commits into
TestSprite:mainfrom
Andy00L:feat/config-file
Open

feat(config): read ~/.testsprite/config for persistent defaults (endpoint_url, output, project_id)#225
Andy00L wants to merge 3 commits into
TestSprite:mainfrom
Andy00L:feat/config-file

Conversation

@Andy00L

@Andy00L Andy00L commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Reopens #179, which was closed by the July 9 release incident (see the
maintainer's comment there). Same branch, same commits (head a07d97b2),
already rebased onto the current main tip and design-approved by
@zeshi-du on the original PR.

What does this PR do?

defaultConfigPath() reserved ~/.testsprite/config but loadConfig never
read it, so every non-credential preference had to be repeated per command.
This implements the aws-cli credentials-vs-config split: profile-sectioned INI
settings (endpoint_url, output, project_id) read via a new
readConfigFileSettings(profile). Precedence is exactly as accepted in
triage — flag > env > config file > built-in default:

  • endpoint_url slots into the loadConfig cascade just above the built-in
    default (below --endpoint-url and TESTSPRITE_API_URL);
  • output becomes the default of the global --output flag (flag still wins);
  • project_id backs --project on the project-scoped test commands, with the
    validation error now naming both options.
    The file is optional by design: missing/unreadable file or section resolves to
    {} and falls through. TESTSPRITE_CONFIG_FILE overrides the path.

Related issue

Fixes #100

Type of change

  • New feature (non-breaking change that adds functionality)

Checklist

  • PR targets the main branch.
  • Commits follow Conventional Commits.
  • npm run lint and npm run format:check pass.
  • npm run typecheck passes.
  • npm test passes and coverage stays at or above the 80% gate.
  • New behavior is covered by unit tests (mock-based; no network).
  • No secrets, API keys, internal endpoints, or personal data are included.

Notes for reviewers

The INI walk is extracted from parseCredentials into a shared parseIniFile
(null-prototype accumulator + __proto__/constructor/prototype section and
key guards); parseCredentials delegates to it, byte-for-byte same behavior —
including the recent CR/LF hardening, which is untouched. No secrets ever live
in the config file (the key stays in credentials). Env-var default for
--project (TESTSPRITE_PROJECT_ID) is intentionally NOT included here — that
is issue #76; per its triage, env will slot above the config file.

Carried over from the original review: once #144 (TESTSPRITE_PROJECT_ID
default, also closed by the incident) re-lands, I will fold the config-file
lookup into its resolveProjectId helper as requested by @zeshi-du.

Summary by CodeRabbit

  • New Features

    • CLI can now read saved project and output preferences from the per-profile config file when flags aren’t provided.
    • Output mode and project selection now automatically follow the active profile for consistent behavior across commands.
  • Bug Fixes

    • Improved config precedence so flag/env/config values are applied in a predictable order.
    • Hardened INI/config parsing to safely ignore malformed or potentially dangerous entries.
  • Tests

    • Added and expanded coverage for config-file settings resolution, profile isolation, and precedence behavior.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 66088fb0-5b8b-441d-bf61-a8b436c1f51a

📥 Commits

Reviewing files that changed from the base of the PR and between 4c96c72 and c333af8.

📒 Files selected for processing (2)
  • src/commands/test.ts
  • src/lib/credentials.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/credentials.ts
  • src/commands/test.ts

Walkthrough

Adds profile-scoped settings from ~/.testsprite/config for API endpoint, output mode, and project ID. Introduces shared hardened INI parsing and wires config values into loadConfig, CLI output defaults, and test project resolution.

Changes

Config-file defaults and hardened parsing

Layer / File(s) Summary
Hardened INI parsing
src/lib/credentials.ts
Adds guarded shared INI parsing and updates credential parsing to consume its section/key output.
Settings reader and configuration precedence
src/lib/config.ts, src/lib/config.test.ts
Adds profile-scoped settings reading, path overrides, endpoint precedence, and tests for profiles, missing files, environment paths, and precedence.
CLI output and project defaults
src/index.ts, src/commands/test.ts
Uses profile config for the --output default and falls back to configured project_id across test list, create, and run-all flows.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant loadConfig
  participant CredentialsFile
  participant readConfigFileSettings
  CLI->>loadConfig: request configuration for profile
  loadConfig->>CredentialsFile: read credentials
  loadConfig->>readConfigFileSettings: read profile settings
  readConfigFileSettings-->>loadConfig: endpointUrl, output, projectId
  loadConfig-->>CLI: resolved apiUrl
Loading

Possibly related PRs

Suggested reviewers: ruili-testsprite, zeshi-du

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: persistent config-file defaults for endpoint_url, output, and project_id.
Linked Issues check ✅ Passed The changes implement config-file defaults for endpoint_url, output, and project_id with shared INI parsing and the required precedence.
Out of Scope Changes check ✅ Passed All notable changes support config-file defaults, parser reuse, or tests for the stated config-precedence work.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@zeshi-du

Copy link
Copy Markdown
Contributor

Reviewed: the INI parser hardening is solid (null-prototype accumulator + explicit proto/constructor/prototype skips), and the endpoint_url chain reads correctly as flag > env > credentials-file > config-file > default.

Sequencing decision (also posted on #249): #249 lands first, then this PR rebases on top, folding the config-file project_id lookup into #249's resolveProjectId helper — per the standing note from the original #179 review — instead of redefining requireProjectId with a new signature (the two PRs currently collide on the same call sites in test.ts). There's also a trivial import-block conflict with main's cancel work in src/index.ts to pick up during the rebase. After that, this merges. Thanks @Andy00L!

@zeshi-du

Copy link
Copy Markdown
Contributor

@Andy00L #249 just merged, so this is unblocked. Two things for the rebase:

  1. The precedence decision is now on main: flag > env > configTESTSPRITE_PROJECT_ID resolution landed in resolveProjectId, so the config-file layer should slot in below env in that same resolver rather than adding a parallel lookup path.
  2. Current branch is conflicting against main (src/index.ts moved under it while this waited).

Rebase and it goes back into normal review — the sequencing hold is lifted.

@Andy00L
Andy00L force-pushed the feat/config-file branch from a07d97b to 4c96c72 Compare July 23, 2026 22:49
@Andy00L

Andy00L commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Rebased on main after #249 (and #272). Config-file project_id folded into resolveProjectId as the third fallback (flag > env > config file) with the profile threaded through; requireProjectId keeps main's assert shape with the enriched message; parseIniFile hardening now sits alongside the new profile-write locking in credentials.ts. Full suite green (2022 tests).

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/commands/test.ts (1)

9179-9183: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep missing-project guidance aligned with config defaults.

The --all message omits the config-file fallback entirely, and the default message omits TESTSPRITE_CONFIG_FILE. Tell users that project_id may be set in ~/.testsprite/config or the override file.

Proposed fix
- '--all requires a project id - pass --project <id> or set TESTSPRITE_PROJECT_ID',
+ '--all requires a project id - pass --project <id>, set TESTSPRITE_PROJECT_ID, or set project_id in ~/.testsprite/config (or TESTSPRITE_CONFIG_FILE)',

- message = 'is required; pass --project <id>, set TESTSPRITE_PROJECT_ID, or set project_id in ~/.testsprite/config',
+ message = 'is required; pass --project <id>, set TESTSPRITE_PROJECT_ID, or set project_id in the config file (~/.testsprite/config or TESTSPRITE_CONFIG_FILE)',

As per path instructions, “TESTSPRITE_PROJECT_ID is still the env fallback, but config-file project_id is now the next fallback.”

Also applies to: 9827-9832

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/commands/test.ts` around lines 9179 - 9183, Update the missing-project
guidance in requireProjectId call sites, including the --all message near
resolveProjectId and the default message around the additionally referenced
location, to mention that project_id can be configured in ~/.testsprite/config
or the TESTSPRITE_CONFIG_FILE override file. Preserve TESTSPRITE_PROJECT_ID as
the environment fallback and keep the existing project and config resolution
behavior unchanged.

Source: Path instructions

🧹 Nitpick comments (1)
src/lib/credentials.ts (1)

108-155: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Solid hardening — null-prototype design correctly neutralizes __proto__ pollution.

The Object.create(null) accumulator plus explicit rejection of __proto__/constructor/prototype section and key names is well-reasoned defense-in-depth, and the final plain-object copy never re-introduces a dangerous key since it only iterates already-filtered entries.

One minor nit: the dangerous-key list (__proto__, constructor, prototype) is duplicated at Lines 124-126 and Line 148. Extracting a shared const DANGEROUS_KEYS = new Set([...]) would prevent the two checks from silently diverging if the list ever needs to change.

♻️ Suggested consolidation
+const DANGEROUS_INI_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
+
 export function parseIniFile(content: string): Record<string, Record<string, string>> {
   ...
-      if (
-        sectionName === '__proto__' ||
-        sectionName === 'constructor' ||
-        sectionName === 'prototype'
-      ) {
+      if (DANGEROUS_INI_KEYS.has(sectionName)) {
         currentEntry = null;
         continue;
       }
   ...
-    if (rawKey === '__proto__' || rawKey === 'constructor' || rawKey === 'prototype') continue;
+    if (DANGEROUS_INI_KEYS.has(rawKey)) continue;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/credentials.ts` around lines 108 - 155, Consolidate the duplicated
dangerous-key checks in parseIniFile by defining one shared DANGEROUS_KEYS set
containing __proto__, constructor, and prototype, then reuse it for both
section-name and raw-key validation. Keep the existing skip behavior unchanged
and ensure both checks use the same centralized list.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/commands/test.ts`:
- Around line 9179-9183: Update the missing-project guidance in requireProjectId
call sites, including the --all message near resolveProjectId and the default
message around the additionally referenced location, to mention that project_id
can be configured in ~/.testsprite/config or the TESTSPRITE_CONFIG_FILE override
file. Preserve TESTSPRITE_PROJECT_ID as the environment fallback and keep the
existing project and config resolution behavior unchanged.

---

Nitpick comments:
In `@src/lib/credentials.ts`:
- Around line 108-155: Consolidate the duplicated dangerous-key checks in
parseIniFile by defining one shared DANGEROUS_KEYS set containing __proto__,
constructor, and prototype, then reuse it for both section-name and raw-key
validation. Keep the existing skip behavior unchanged and ensure both checks use
the same centralized list.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 087a78c0-8ab9-4a71-9598-6f92dd231b46

📥 Commits

Reviewing files that changed from the base of the PR and between a07d97b and 4c96c72.

📒 Files selected for processing (5)
  • src/commands/test.ts
  • src/index.ts
  • src/lib/config.test.ts
  • src/lib/config.ts
  • src/lib/credentials.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/lib/config.test.ts
  • src/index.ts
  • src/lib/config.ts

@Andy00L

Andy00L commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Lint red fixed (the rebase resolution had not been through prettier). Also addressed the review notes: both missing-project messages now mention the config-file fallback incl. TESTSPRITE_CONFIG_FILE, and the dangerous-key checks in parseIniFile share one DANGEROUS_INI_KEYS set.

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.

[Hackathon] Read ~/.testsprite/config for persistent defaults (output, endpoint, project)

2 participants