Skip to content

Add CURLTask(_:allowing:) to run a command without the flags that touch the machine - #430

Merged
o-nnerb merged 2 commits into
mainfrom
curl-allowing
Oct 19, 2026
Merged

o-nnerb merged 2 commits into
mainfrom
curl-allowing

Conversation

@o-nnerb

@o-nnerb o-nnerb commented Oct 18, 2026

Copy link
Copy Markdown
Member

What

CURLTask(_:allowing:): a curl command from a source you do not control can run with none of the flags that touch the machine or weaken the connection. (Audit E17.) Additive: CURLTask(_:) allows everything, as it always did.

// Nothing it could read, redirect or weaken.
try await CURLTask(pasted, allowing: [])
    .result()

// The same, but it may name a proxy.
try await CURLTask(pasted, allowing: .proxy)
    .result()

CURLTask.Capabilities is an OptionSet:

Capability Flags it covers
.localFiles -F name=@path (relative paths too, which resolve against the working directory), --cacert, --cert / -E, --key
.disabledTLSVerification -k / --insecure
.proxy -x / --proxy
.dnsOverrides --resolve
.all every one of the above, what CURLTask(_:) allows

A flag that needs a capability the task was not given throws CURLParsingError(.unsupportedFlag, token: <the flag>). It happens in the loop over the tokens of CURLCommandParser.parseCommand, so before any file is opened and before the session or the request is built.

Decisions

  • .unsupportedFlag, no new case in CURLParsingError.Context. A new case would be source-breaking for anyone who switches over it without default, and this change is meant to be purely additive. The cost: the context does not tell "not in the subset" from "not allowed here"; the token is the flag in both. Its documentation says so.
  • -F name=@path is a local file, a relative path included. -F name=value, a field of plain text, needs nothing.
  • -o / --output and the other flags that only shape curl's output stay accepted and ignored, with no capability: they do not touch the request, the response or this machine.
  • No CURLTask.untrusted(_:). allowing: [] says the same, and the set can grow with the library without a second spelling.

Tests

CURLTaskCapabilitiesTests (10 tests):

  • each of the twelve spellings of a flag is refused with [], and the error carries that flag as the token;
  • a capability covers its own flags and not the others (.proxy does not allow -k, .localFiles does not allow --resolve, and so on);
  • the matching capability allows the flag; .all allows everything at once; parseCommand(_:) without allowing: allows everything;
  • [] still allows a plain request (method, headers, a body, -u, -L, --compressed, -s, -o) and a form of plain fields;
  • a refused -F file=@/nonexistent/... is never opened: with .localFiles the same command fails opening the file with an error that is not a CURLParsingError, with [] it is refused first;
  • CURLTask(_:allowing: []) throws before any network I/O;
  • the capabilities are distinct bits and .all is their union.

Checked by turning every require into a no-op: the refusal tests, the two "other flags" tests, the never-opened one and the task one fail (51 issues).

macOS full suite and the URLSession-only build pass locally. swift format lint --strict is clean on the CURL sources and tests.

🤖 Generated with Claude Code

…ch the machine

CURLTask.Capabilities (.localFiles, .disabledTLSVerification, .proxy,
.dnsOverrides, .all) says what a command may do. A flag that needs a capability
the task was not given throws CURLParsingError.unsupportedFlag while the
command is parsed, before a file is opened. CURLTask(_:) allows everything.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@codecov

codecov Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.76%. Comparing base (6fcd41d) to head (d8c3851).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #430      +/-   ##
==========================================
+ Coverage   94.63%   94.76%   +0.13%     
==========================================
  Files         464      464              
  Lines       19367    19387      +20     
==========================================
+ Hits        18327    18372      +45     
+ Misses       1040     1015      -25     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@o-nnerb
o-nnerb merged commit db15832 into main Oct 19, 2026
19 of 20 checks passed
@o-nnerb
o-nnerb deleted the curl-allowing branch October 19, 2026 00:42
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