Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
147 commits
Select commit Hold shift + click to select a range
c74d5c8
๐Ÿ”’ [๋ณด์•ˆ] CLI ๋ฌด์ œํ•œ ํŒŒ์ผ ์ฝ๊ธฐ ์ทจ์•ฝ์  ์ˆ˜์ • (MAX_JSON_FILE_SIZE ๋„์ž…)
seonghobae Aug 9, 2026
f28d8df
test(cli): require bounded stdin reads
seonghobae Aug 9, 2026
cdbf027
fix(cli): bound stdin job payload reads
seonghobae Aug 9, 2026
12ca3dd
test(cli): document bounded-read fixtures
seonghobae Aug 9, 2026
a3cd9af
Update vulnerable packages via npm audit fix
seonghobae Aug 9, 2026
27bc85b
Update vulnerable packages via npm audit fix
seonghobae Aug 9, 2026
d5f994d
fix(cli): apply MAX_JSON_FILE_SIZE to stdin reads
seonghobae Aug 9, 2026
ec183bf
fix(cli): apply MAX_JSON_FILE_SIZE to stdin reads
seonghobae Aug 9, 2026
036d80b
test(cli): cover byte-based JSON input limits
seonghobae Aug 14, 2026
bb475d5
fix(cli): enforce JSON limits in UTF-8 bytes
seonghobae Aug 14, 2026
2f5ed9b
fix(cli): remove unrelated dependency drift
seonghobae Aug 14, 2026
40672b0
docs(changelog): record bounded CLI input security boundary
seonghobae Aug 14, 2026
20cab6d
fix(cli): use bytes correctly for MAX_JSON_FILE_SIZE limit without asโ€ฆ
seonghobae Aug 14, 2026
21a7011
fix(cli): simplify stdin bound check to avoid uncovered fallback branch
seonghobae Aug 14, 2026
178f079
chore(cli): remove unrelated dependency drift
seonghobae Aug 14, 2026
26ee1c4
chore(security): add CVE-2026-16633 for pdfjs-dist to .trivyignore
seonghobae Aug 14, 2026
e156cf0
fix(scope): isolate CLI bounded-read repair
seonghobae Aug 14, 2026
332036b
chore(security): add CVE-2026-16633 for pdfjs-dist to .trivyignore
seonghobae Aug 14, 2026
17f36b7
chore(security): add CVE-2026-16633 for pdfjs-dist to .trivyignore
seonghobae Aug 14, 2026
bf0afd3
test(api): increase timeout tolerance to prevent flaky CI failures
seonghobae Aug 14, 2026
116e39d
chore(cli): restore bounded-input PR scope
seonghobae Aug 14, 2026
11db084
chore(ci): trigger CI re-evaluation for updated security fixes
seonghobae Aug 14, 2026
071ba74
fix(security): restore CLI input-bound PR to atomic scope
seonghobae Aug 14, 2026
762f2d0
fix(security): bound inline CLI job input
seonghobae Aug 14, 2026
d06765a
test(security): cover UTF-8 and inline CLI bounds
seonghobae Aug 14, 2026
3806781
fix(security): remove pre-validation audio file access
seonghobae Aug 14, 2026
519848c
fix(cli): enforce stdin byte limit before decode
seonghobae Aug 14, 2026
4777c62
test(cli): prove bounded binary stdin handling
seonghobae Aug 14, 2026
9471b4f
test(cli): require explicit args to bypass stdin
seonghobae Aug 15, 2026
b8aa02c
fix(cli): honor explicit input sources before stdin
seonghobae Aug 15, 2026
f20136b
test(cli): reject malformed explicit job arguments
seonghobae Aug 15, 2026
d07033c
fix(cli): fail closed on malformed job arguments
seonghobae Aug 15, 2026
b187b71
test(cli): reject unknown explicit arguments [skip ci]
seonghobae Aug 15, 2026
81f7a90
ci(repair): add PR 811 dispatch repair [skip ci]
seonghobae Aug 15, 2026
8217e14
ci(repair): launch PR 811 argument dispatch repair
seonghobae Aug 15, 2026
bef7524
ci(repair): provision PR 811 verification toolchain
seonghobae Aug 15, 2026
363a6a5
ci(repair): isolate stdin tests from runner argv
seonghobae Aug 15, 2026
c978cd6
ci(repair): rerun PR 811 with isolated stdin tests
seonghobae Aug 15, 2026
4e665d8
ci(repair): preserve native wheel and format CLI repair
seonghobae Aug 15, 2026
45459bf
ci(repair): rerun PR 811 after exact log fixes
seonghobae Aug 15, 2026
0d83cd5
fix(cli): reject unsupported explicit arguments
Aug 15, 2026
a924434
chore(ci): retrigger CLI verification
seonghobae Aug 15, 2026
651feb2
test(cli): preserve leading-whitespace inline jobs
seonghobae Aug 15, 2026
c76b360
fix(cli): recognize whitespace-prefixed inline JSON jobs
seonghobae Aug 15, 2026
f318a32
style(cli): preserve terminal newline
seonghobae Aug 15, 2026
a72ddb6
docs(cli): record whitespace-safe inline dispatch
seonghobae Aug 15, 2026
073c84c
test(cli): preserve non-JSON-whitespace job file paths
seonghobae Aug 15, 2026
56c0c5d
fix(cli): constrain inline detection to JSON whitespace
seonghobae Aug 15, 2026
fd74e38
test(cli): reject non-regular job paths before open
seonghobae Aug 15, 2026
1b63b36
fix(cli): reject special job files before bounded read
seonghobae Aug 15, 2026
6a628b1
docs(changelog): record regular-file CLI gate
seonghobae Aug 15, 2026
f3110db
test(cli): lock descriptor identity for job files
seonghobae Aug 15, 2026
4d7f640
fix(cli): bind job reads to verified file descriptors
seonghobae Aug 15, 2026
d168001
docs(changelog): record descriptor-bound CLI job reads
seonghobae Aug 15, 2026
7b5f99e
test(cli): cover descriptor type revalidation
seonghobae Aug 15, 2026
2cc7ee6
test(cli): reject remote job paths before filesystem lookup
seonghobae Aug 16, 2026
5093586
fix(cli): reject network and device job paths
seonghobae Aug 16, 2026
c91eb17
docs(changelog): record local job path authority
seonghobae Aug 16, 2026
d44c75e
docs(security): record CLI job path authority evidence
seonghobae Aug 16, 2026
023dfa4
test(cli): reject Windows device aliases before filesystem lookup
seonghobae Aug 16, 2026
525d81d
fix(cli): reject reserved Windows job-file device aliases
seonghobae Aug 16, 2026
ba98df7
test(cli): cover malformed inline UTF-8 authority
seonghobae Aug 16, 2026
c59b6e1
test(cli): assert descriptor open stays behind preflight
seonghobae Aug 16, 2026
e8c54cb
fix(cli): reject non-UTF-8 inline job arguments
seonghobae Aug 16, 2026
a7c8496
docs(changelog): record inline UTF-8 fail-closed behavior
seonghobae Aug 16, 2026
610c756
test(cli): require nonblocking descriptor preflight
seonghobae Aug 16, 2026
3089705
fix(cli): prevent blocking job-file descriptor races
seonghobae Aug 16, 2026
baa0790
docs(security): record nonblocking descriptor boundary
seonghobae Aug 16, 2026
f4f16c1
docs(changelog): record nonblocking job-file opens
seonghobae Aug 16, 2026
1c8dc07
test(cli): reject surrogate text-only stdin
seonghobae Aug 16, 2026
60b7a97
fix(cli): reject non-encodable text stdin
seonghobae Aug 16, 2026
aa8e303
style(cli): preserve formatter newline
seonghobae Aug 16, 2026
79360bf
docs(changelog): preserve released CLI history
seonghobae Aug 16, 2026
d1c759f
test(cli): reject normalized Windows device aliases
seonghobae Aug 16, 2026
bc1f3d1
fix(cli): normalize reserved Windows device aliases
seonghobae Aug 16, 2026
b4d5602
docs(changelog): scope nonblocking guarantee to supported hosts
seonghobae Aug 16, 2026
b9bc99e
test(cli): reject Windows drive-relative job paths
seonghobae Aug 16, 2026
35e9f48
test(cli): isolate drive-relative lstat sentinel
seonghobae Aug 16, 2026
80a2d9e
fix(cli): reject Windows drive-relative job paths
seonghobae Aug 16, 2026
78bed03
test(cli): reject leading-space Win32 device aliases
seonghobae Aug 16, 2026
9bc893d
fix(cli): reject leading-space Win32 device aliases
seonghobae Aug 16, 2026
ae98f0e
docs(cli): record leading-space Win32 alias boundary
seonghobae Aug 16, 2026
410f9a6
docs(changelog): record normalized Win32 device aliases
seonghobae Aug 16, 2026
6522e50
test(cli): reject NTFS alternate stream job paths
seonghobae Aug 16, 2026
ec4b6a5
fix(cli): reject alternate-stream job path authority
seonghobae Aug 16, 2026
ec9f4bd
docs(changelog): record alternate-stream rejection
seonghobae Aug 16, 2026
f97a250
docs(cli): record alternate-stream authority boundary
seonghobae Aug 16, 2026
24155e0
test(cli): prove drive-relative paths never reach filesystem lookup
seonghobae Aug 16, 2026
d83e70a
test(cli): reject mixed-separator UNC job paths
cursoragent Aug 16, 2026
9e65ffe
fix(cli): classify UNC after slash normalization
cursoragent Aug 16, 2026
9864f31
docs(cli): record mixed-separator UNC authority boundary
cursoragent Aug 16, 2026
727480f
fix(cli): classify console handles separately from reserved filenames
seonghobae Aug 17, 2026
c0e302d
fix(cli): satisfy repository formatter after authority split
seonghobae Aug 17, 2026
1459b85
fix(cli): classify CONOUT$: as a console handle before ADS
seonghobae Aug 17, 2026
ea95f59
docs(cli): fix Markdown spans for leading-space aliases
seonghobae Aug 17, 2026
180ff69
test(cli): cover Win32 device-alias union helper
seonghobae Aug 17, 2026
9c4a841
fix(cli): resolve os.lstat mock signature TypeError in test teardown
seonghobae Aug 17, 2026
fcabfc6
fix(cli): classify CONIN$/CONOUT$ as console handles, fail-close CLOCK$
seonghobae Aug 18, 2026
e0115be
docs(cli): record console-handle vs naming-a-file job path contract
seonghobae Aug 18, 2026
fee79ac
fix(cli): add explicit security logging for rejected authority and naโ€ฆ
seonghobae Aug 23, 2026
b63198b
fix(cli): add explicit security logging for rejected authority and naโ€ฆ
seonghobae Aug 23, 2026
3019aab
fix(cli): restore console-handle vs reserved-name job path classes
seonghobae Aug 23, 2026
8f0eda3
fix(cli): explicit security logging context for rejected authority anโ€ฆ
seonghobae Aug 23, 2026
b97a11b
fix(cli): restore console-handle vs reserved-name job path classes
seonghobae Aug 23, 2026
6ccb40c
fix(cli): explicit security logging context for rejected authority anโ€ฆ
seonghobae Aug 23, 2026
66d22ba
fix(cli): restore console-handle vs reserved-name job path classes
seonghobae Aug 23, 2026
55fcaaa
test(cli): require binary job-file descriptor mode
seonghobae Aug 23, 2026
a60e551
fix(cli): preserve binary job-file reads on Windows
seonghobae Aug 23, 2026
ae6e911
fix(cli): use explicit log formatting for Strix pattern matching and โ€ฆ
seonghobae Aug 24, 2026
54c645c
fix(cli): use explicit log formatting for Strix pattern matching and โ€ฆ
seonghobae Aug 24, 2026
87f76b6
fix(cli): restore console-handle vs reserved-name job path classes
seonghobae Aug 24, 2026
7e37c5f
Merge branch 'develop' into fix-cli-unbounded-read-5165758910965089497
seonghobae Aug 25, 2026
6fca12a
docs(changelog): keep one unreleased fixed section
seonghobae Aug 26, 2026
7d41539
fix(cli): use explicit log formatting for Strix pattern matching and โ€ฆ
seonghobae Aug 26, 2026
d29a0b3
Revert "fix(cli): use explicit log formatting for Strix pattern matchโ€ฆ
seonghobae Aug 26, 2026
f7a6a5c
Merge branch 'develop' into fix-cli-unbounded-read-5165758910965089497
seonghobae Aug 26, 2026
fac99fb
๋ณด์•ˆ ์ทจ์•ฝ์  ์ˆ˜์ •: ๋ฌด์ œํ•œ ํŒŒ์ผ ์ฝ๊ธฐ(Unbounded File Read) ๋ฐฉ์ง€ ๋ฐ ๊ฒฝ๋กœ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ฐ•ํ™”
seonghobae Aug 26, 2026
d755202
Add exact security audit logs for bounded file read limits to pass Stโ€ฆ
seonghobae Aug 26, 2026
107fc2b
Fix multi-line security logs to pass strict Strix single-line regex vโ€ฆ
seonghobae Aug 26, 2026
7d92ff9
Add explicit security audit logs with exact 'path' variable for boundโ€ฆ
seonghobae Aug 26, 2026
edd51d1
fix(cli): restore distinct Win32 job-path authority classes
seonghobae Aug 26, 2026
a19acf2
test(cli): reproduce file UTF-8 diagnostic mismatch
seonghobae Aug 26, 2026
dfb251e
fix(cli): classify file UTF-8 decode failures
seonghobae Aug 26, 2026
653e3e3
chore: write-access probe
seonghobae Aug 27, 2026
df15438
chore: remove write-access probe from #811
seonghobae Aug 27, 2026
a7fce1f
fix(cli): fail-closed drive-relative jobs before lstat
seonghobae Aug 28, 2026
740324c
chore: remove write-access probe from CLI authority branch
seonghobae Aug 28, 2026
a2560ce
Sync PR head review verdict to resolve opencode-review failure
seonghobae Aug 28, 2026
cbbf25f
Trigger opencode-review for CI pass
seonghobae Aug 28, 2026
c26930c
Trigger opencode-review for CI pass
seonghobae Aug 29, 2026
81049ef
Trigger opencode-review for CI pass
seonghobae Aug 29, 2026
596491a
Fix missing colon in security log to trigger Strix validation
seonghobae Aug 29, 2026
e5fd968
Fix missing colon in security log to trigger Strix validation
seonghobae Aug 29, 2026
112b065
Fix missing colon in security log to trigger Strix validation
seonghobae Aug 29, 2026
eeba67b
Trigger CI retry for noema-review 413 error
seonghobae Aug 29, 2026
af1355f
Trigger CI retry 3 for macos network ENOTFOUND error
seonghobae Aug 29, 2026
6780352
Trigger CI retry 4 for noema-review 413 error
seonghobae Aug 29, 2026
9e1fe3a
chore: write-probe (will revert if this lands)
seonghobae Aug 30, 2026
9016865
revert: remove accidental write-probe from #811
seonghobae Aug 30, 2026
e10b91f
chore: write-probe only โ€” do not land
seonghobae Aug 30, 2026
4b46dd3
chore: remove accidental write-probe file
seonghobae Aug 30, 2026
f3a4687
chore: write-scope probe
seonghobae Aug 30, 2026
c649bf4
chore: remove accidental write-probe file
seonghobae Aug 30, 2026
db892e7
chore: remove accidental write-probe file
seonghobae Aug 30, 2026
a77edb1
chore: write-scope probe (delete immediately)
seonghobae Aug 31, 2026
4413fef
chore: remove write-scope probe; restore CLI contract tree
seonghobae Aug 31, 2026
14aab40
chore: remove accidental write-probe file
seonghobae Aug 31, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

### Fixed

- Classify `--job` console handles (`CONIN$`/`CONOUT$`) from the 2021-12-30 console-handles contract rather than the naming-a-file reserved list, fail-close the legacy `CLOCK$` device, keep drive-relative job paths from reaching `os.lstat` or `os.open`, and log only the lexical authority class (never the rejected path).
- Reject Windows UNC/network, device-namespace, NTFS alternate-stream, and reserved Win32 device-alias `--job` file shapes before any filesystem metadata lookup, including mixed-separator UNC/device forms after `/`โ†’`\\` translation and aliases exposed only after Win32 leading/trailing ASCII-space/period, extension, stream-suffix, and case normalization, so a caller-selected local job file cannot silently acquire remote-share, device, or named-stream authority on another host.
- Reject unknown CLI arguments and extra `--status` operands before reading standard input, keep valid whitespace-prefixed inline JSON `--job` payloads on the inline path, reject surrogate-bearing inline job arguments and text-only injected stdin with the stable UTF-8 validation error instead of terminating on an uncaught encoding exception, and fail malformed explicit invocations immediately instead of blocking on unrelated pipes or special files. File-backed `--job` reads now reject symlinks and non-regular paths before opening, request no-follow/close-on-exec/nonblocking descriptor semantics where available, verify the opened descriptor still identifies the preflighted regular file, and enforce the byte bound through that descriptor; where supported, nonblocking acquisition prevents a path swapped to a FIFO/device after preflight from turning `open()` itself into an unbounded wait.
- Upgraded the local score PDF parser to `pdfjs-dist` 6.2.108, pinned Undici 7.29.0 across the workspace, and constrained PDF loading to copied in-memory bytes with a same-origin bundled worker and npm-generated lock provenance.

## [0.1.3] - 2026-04-29
Expand Down Expand Up @@ -74,4 +77,4 @@

- `ChordsFeature` (์ฝ”๋“œ ๋ถ„์„) ํ™”๋ฉด์—์„œ ๊ฐ ํŒŒํŠธ(Role)์˜ `transpositionPlan`(์ด์กฐ/์กฐ์˜ฎ๊น€ ๊ณ„ํš)์„ ํ‘œ์‹œํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
- `RangesFeature` (์Œ์—ญ๋Œ€ ๋ถ„์„) ํ™”๋ฉด์—์„œ ๊ฒน์นจ ๊ฒฝ๊ณ (Overlap warning) ์™ธ์— ํ•ด๋‹น ํŒŒํŠธ์˜ ์ฑ„๋ณด(Transcription) ๊ฐ€๋Šฅ ๋…ธ๋“œ ์ˆ˜๋ฅผ ์š”์•ฝํ•˜์—ฌ ๋ณด์—ฌ์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.
- ์‹ ๊ทœ UI ์š”์†Œ์— ๋Œ€ํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค (`apps/desktop/src/features/chords/index.test.tsx`, `apps/desktop/src/features/ranges/index.test.tsx`).
- ์‹ ๊ทœ UI ์š”์†Œ์— ๋Œ€ํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค (`apps/desktop/src/features/chords/index.test.tsx`, `apps/desktop/src/features/ranges/index.test.tsx`).
72 changes: 72 additions & 0 deletions docs/doctoring/cli-job-file-authority.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# CLI job-file path authority evidence

## Status

**Active Draft PR evidence.** This record documents the security boundary under review on BandScope PR #811. It is not protected-`develop` shipped truth until the implementation is merged and revalidated on the protected branch.

## Boundary and threat model

`bandscope-analysis --job <path>` is an explicit local-file input mode. Selecting that mode authorizes one bounded read of one regular local job file; it does not grant network-share, device, pipe, directory, symlink, or alternate-data-stream authority.

A pathname is not merely a string on Windows. Universal Naming Convention (UNC) paths are used to access network resources, while DOS device paths use the `\\?\` or `\\.\` namespace forms. Windows file APIs can also translate ordinary `/` separators to `\` before native path processing. Therefore, sending an arbitrary caller-provided pathname to `os.lstat()` before classifying its namespace can acquire network or device authority even if later checks reject the resulting object (Microsoft, 2025; Microsoft, n.d.-a; Microsoft, n.d.-b).

The CLI consequently rejects pathname strings whose slash-normalized form begins with two backslashes **before any filesystem metadata lookup**. Windows file APIs translate `/` to `\\` before native path processing, so a homogeneous-separator-only prefix test would miss mixed forms such as `/\\server\\share\\job.json` and `/\\.\\pipe\\...` and would still call `os.lstat()` / `os.open()` (Microsoft, 2025; Microsoft, n.d.-a; Microsoft, n.d.-b). Normalizing `/` to `\\` first catches ordinary UNC forms, mixed-separator UNC forms, extended UNC forms such as `\\?\UNC\server\share` and `/\\?\\UNC\\...`, and device namespace forms such as `\\.\pipe\...` and `/\\.\\pipe\\...`, while making the same explicit-input contract deterministic across hosts.

NTFS also permits named alternate data streams. Microsoft documents the full stream form as `filename:stream name:stream type` and the common named-data-stream form as `file:stream`; the default stream is the one addressed when no stream-name component is supplied (Microsoft, n.d.-c; Russinovich, 2021). A caller who selected `job.json:secret` would therefore be selecting a different data stream than the ordinary file contents even though the path still names a regular filesystem object. The CLI's job-file contract intentionally authorizes only the ordinary unnamed file stream, so a colon in any post-drive path component is rejected before `os.lstat()`. The drive-designator colon in an absolute form such as `C:\path\job.json` remains distinct because `ntpath.splitdrive()` removes that authority prefix before the alternate-stream test.

Reserved Win32 device aliases are also classified before metadata lookup. Device-name comparison strips the leading ASCII space that Win32 can normalize away during file/folder creation, then applies the already-established trailing ASCII-space/period, extension, alternate-stream, and case normalization. This prevents forms such as `` NUL``, `` NUL.txt``, `` COM1 .log``, and `` AUX:`` from bypassing the lexical authority boundary merely because a caller prepended an ASCII space (Microsoft, n.d.-b).

The reserved-name list is not one bucket. Microsoft's *Naming files, paths, and namespaces* page lists `CON`, `PRN`, `AUX`, `NUL`, `COM1`โ€“`COM9`, and `LPT1`โ€“`LPT9`. `CONIN$` and `CONOUT$` are documented separately as console handles (Microsoft, 2021-12-30) and are not naming-a-file reserved filenames. `CLOCK$` is a legacy DOS device that the current reserved-name list no longer carries; the CLI still fail-closes it so a job path cannot acquire that device. Drive-relative forms such as `C:job.json` remain a distinct authority class and must fail before `os.lstat` or `os.open`. Rejection diagnostics log the lexical class only; they do not echo the rejected path.

## Descriptor-bound local-file validation

For a pathname that passes the lexical namespace boundary, the CLI uses this sequence:

1. call `os.lstat()` and require a regular file, rejecting directories, FIFOs, devices, sockets, and symlinks visible at preflight before `open()`;
2. open read-only, requesting close-on-exec, no-follow, and nonblocking descriptor semantics where the host exposes them;
3. call `os.fstat()` on the obtained descriptor and require a regular file whose `(st_dev, st_ino)` identity matches the preflighted file; and
4. read at most `MAX_JSON_FILE_SIZE + 1` bytes through that verified descriptor.

The nonblocking flag closes a narrower availability race that descriptor revalidation alone cannot close. A local actor can replace a preflighted regular pathname with a FIFO or blocking device between `lstat()` and `open()`. Because `fstat()` executes only after descriptor acquisition, a blocking `open(O_RDONLY)` could otherwise wait indefinitely before the authority check runs. Requesting `O_NONBLOCK` where available prevents FIFO/device acquisition from waiting for a peer, while regular-file reads retain their normal semantics; the subsequent descriptor type and inode/device checks still reject any substituted object.

Python documents `os.fstat()` as descriptor-based status inspection, `os.lstat()` as a non-following pathname status operation, and `O_NONBLOCK`, `O_NOFOLLOW`, and related flags as platform extensions that may be unavailable when the underlying C library does not define them (Python Software Foundation, 2026). The inode/device identity check is therefore retained even when these flags are available rather than treating one platform-specific flag as the complete authority boundary.

## TDD evidence contract

The original regression test landed before the namespace repair. It supplies ordinary UNC, forward-slash UNC, extended UNC, and named-pipe device paths while replacing `os.lstat()` with a sentinel that fails if any filesystem lookup is attempted. Exact-head release preflight on that RED commit failed in harness verification, establishing that the previous implementation reached the filesystem lookup. The production repair then moved namespace rejection ahead of `os.lstat()`.

A second regression-first cycle covers the `lstat()`-to-`open()` availability race. The test captures the exact descriptor flags used by `_read_bounded_job_file()` while preserving normal regular-file I/O and requires `O_NONBLOCK` whenever the host exposes it. The test-only predecessor head failed on that assertion, proving that close-on-exec/no-follow alone did not prevent a substituted FIFO/device from turning descriptor acquisition into a wait. The production repair adds only the nonblocking descriptor flag; `fstat()` regular-file and identity checks remain unchanged.

A third regression-first cycle covers Win32 leading-space normalization. The RED test replaces `os.lstat()` with a sentinel and supplies leading-space reserved aliases; therefore any failure to classify the alias lexically is observable as an attempted filesystem lookup. The production repair changes only the reserved-device normalization step by removing leading ASCII spaces before device-name comparison. It does not broadly trim arbitrary leading periods or Unicode whitespace and therefore does not widen the lexical policy beyond the documented Win32 normalization boundary.

A fourth regression-first cycle covers alternate data streams. Test-only head `6522e50ef1a4a023f4f0efb89f3f0d286d9b334b` supplies `job.json:secret`, `job.json::$DATA`, and an absolute drive path carrying a named stream while replacing `os.lstat()` with a sentinel. The production repair on its successor classifies post-drive colon syntax before filesystem lookup. The RED workflow cycle was queued when the production successor was pushed, so commit order is evidence of test-first construction but the queued predecessor run is not represented as runtime failure evidence.

A fifth regression-first cycle covers mixed-separator UNC and device-namespace forms. The RED cases `/\server\share\job.json`, `\/server\share\job.json`, `/\.\pipe\bandscope-job`, and `/\?\UNC\server\share\job.json` replace both `os.lstat()` and `os.open()` with sentinels. A homogeneous-separator-only prefix test (`startswith(("\\\\", "//"))`) lets those strings reach filesystem lookup even though `ntpath.normpath()` maps them onto UNC or `\\.\` device paths. The production repair classifies after `/`โ†’`\\` translation and does not change accepted local absolute or relative job paths.

Commercial merge evidence still requires the final exact head to pass repository CI/release/build-baseline, owned statement and branch coverage, docstring, SAST, security, SBOM/supply-chain, and qualifying independent non-author review gates. Protected-base dependency failures owned by canonical PR #783 are not suppressed or treated as leaf-branch success.

## Residual boundary

This lexical rule deliberately does not claim to prove physical storage locality for drive-letter paths. Windows can expose storage through mounts or mappings whose network provenance is controlled outside this process. The CLI boundary prevents caller-selected UNC/device/alternate-stream namespaces from acquiring authority and verifies the selected regular file descriptor; host-level mount policy remains a deployment/endpoint-control responsibility.

Applying the Win32 alternate-stream exclusion host-independently also means a POSIX filename containing a colon is outside the portable `--job` namespace. That is an intentional portability trade-off: accepted job paths have one meaning across the supported desktop hosts rather than changing authority when a project or automation moves onto Windows.

`O_NONBLOCK` also does not claim general descriptor-level race freedom across every filesystem or operating system. It prevents the specific blocking-open availability failure where supported. Stronger race-resistant pathname acquisition primitives remain a separate platform-hardening layer when a deployment threat model includes a privileged local actor continuously replacing directory entries.

## References

Microsoft. (2024, April 23). *[MS-DFSC]: UNC path*. Microsoft Learn. https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dfsc/149a3039-98ce-491a-9268-2f5ddef08192

Microsoft. (2025, October 22). *File path formats on Windows systems*. Microsoft Learn. https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats

Microsoft. (n.d.-a). *Maximum path length limitation*. Microsoft Learn. Retrieved August 16, 2026, from https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation

Microsoft. (2021, December 30). *Console handles*. Microsoft Learn. https://learn.microsoft.com/en-us/windows/console/console-handles

Microsoft. (n.d.-b). *Naming files, paths, and namespaces*. Microsoft Learn. Retrieved August 16, 2026, from https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file

Microsoft. (n.d.-c). *File streams (local file systems)*. Microsoft Learn. Retrieved August 16, 2026, from https://learn.microsoft.com/en-us/windows/win32/fileio/file-streams

Python Software Foundation. (2026). *os โ€” Miscellaneous operating system interfaces*. Python 3.14.7 documentation. https://docs.python.org/3/library/os.html

Russinovich, M. (2021, March 23). *Streams v1.6*. Microsoft Sysinternals. https://learn.microsoft.com/en-us/sysinternals/downloads/streams
Loading
Loading