Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
55 changes: 46 additions & 9 deletions .github/SECURITY.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,50 @@
# Security Policy
# Security policy

## Supported Versions
sphinx-argparse-cli is a Sphinx extension that renders the command-line interface an `argparse` parser defines. This
policy says how to report a security problem and how we decide whether a report is one.

| Version | Supported |
| ------- | ------------------ |
| 1.10 + | :white_check_mark: |
| < 1.10 | :x: |
## Reporting a vulnerability

## Reporting a Vulnerability
**Do not open a public issue for a security problem.** Use
[GitHub's private vulnerability reporting](https://github.com/tox-dev/sphinx-argparse-cli/security/advisories/new). If
you do not have a GitHub account, or you are a Tidelift subscriber, report through the
[Tidelift security contact](https://tidelift.com/security) instead; Tidelift coordinates the fix and the disclosure with
us. If neither works for you, email [gaborjbernat@gmail.com](mailto:gaborjbernat@gmail.com).

To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift
will coordinate the fix and disclosure.
Include what the attacker controls and what they gain, the steps or a proof of concept, and the versions and platform
you tested. Write the report yourself; unreviewed tool or model output takes longer to triage.

## What to expect

Volunteers maintain sphinx-argparse-cli, with no on-call rotation. We aim to acknowledge a report within **5 working
days** and assess it within **15 working days**. Fixes are developed in a private fork attached to the draft advisory,
ship in a new release, and the advisory, with a CVE requested through GitHub, goes out with that release. The default
embargo is **90 days** from the report; we agree any change with the reporter. We credit reporters in the advisory under
the name they choose, or not at all. There is no bug bounty.

## Supported versions

Only the latest release receives fixes. Confirm the problem reproduces on it before reporting.

## Vulnerability or bug

A report is a vulnerability when an attacker who controls only an input that the [threat model](THREAT_MODEL.md) lists
as untrusted breaks a guarantee sphinx-argparse-cli makes. A report that first needs control of something the threat
model trusts, such as the documented project's code or the Sphinx configuration, is a bug: we fix it in the open and
publish no advisory. Classify by who supplies the dangerous input, not by how bad the outcome sounds.

**In scope**

- The directive importing a module, or calling a function, other than the ones its `:module:` and `:func:` options name.
- The extension reading or writing files beyond the Sphinx build's own outputs.

**Out of scope**

- Code that runs when the directive imports the module and calls the parser factory: that is the documented project's
code, trusted like every module autodoc imports.
- Markup in help strings: the extension parses them as reStructuredText on purpose, so they are trusted like the code
that defines them.
- Markup the documentation author writes around the directive.
- Sphinx and docutils behavior.

If you cannot tell which side a finding falls on, report it privately and we will decide.
90 changes: 90 additions & 0 deletions .github/THREAT_MODEL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Threat model

This model says what sphinx-argparse-cli trusts, where untrusted input enters, and which guarantees hold at each
boundary, so a report can be classified as a vulnerability or a bug. [SECURITY.md](SECURITY.md) covers reporting; if the
two disagree, SECURITY.md wins and we fix this file.

## How sphinx-argparse-cli works

The `sphinx_argparse_cli` directive imports the module named by `:module:`, gets the parser either by calling the
function named by `:func:` or, with `:hook:`, by running that function while `ArgumentParser.parse_known_args` and
`parse_known_intermixed_args` are patched to capture the parser. It walks the parser's actions and subcommands and emits
docutils nodes for them, parsing help text as reStructuredText, and writes its stylesheet into the build output.

```mermaid
flowchart LR
conf[("conf.py and .rst<br/>(trusted)")] --> ext["sphinx-argparse-cli"]
ext -->|"import :module:, call :func:"| code["Project code<br/>(trusted)"]
code -->|"ArgumentParser: help, choices"| ext
ext -->|"docutils nodes"| html["Built docs"]
classDef trusted fill:#cfe4ff,stroke:#1f6feb,color:#0b1f3a;
classDef boundary fill:#ffe3a3,stroke:#d29200,color:#3a2c00;
class conf,ext,code trusted;
class html boundary;
```

## Compared with similar tools

We drew the boundary where comparable projects in other ecosystems draw theirs. The shared rule, stated by the
[Node.js threat model](https://github.com/nodejs/node/blob/main/SECURITY.md#the-nodejs-threat-model), is that a report
which first needs a trusted element compromised is out of scope; the first triage question, as
[DOMPurify](https://github.com/cure53/DOMPurify/blob/main/SECURITY.md#what-we-consider-a-vulnerability) puts it, is what
the attacker controls.

| Project | Language | Where it draws the line |
| ------------------------------------------------------------------------------------ | ---------- | ------------------------------------------------------------------------------------------------------------------- |
| [Sphinx autodoc](https://www.sphinx-doc.org/en/stable/usage/extensions/autodoc.html) | Python | Imports the modules it documents and warns that their import-time side effects run; the documented code is trusted. |
| [TypeDoc](https://github.com/TypeStrong/typedoc/security/policy) | TypeScript | Documentation generator; patches the latest minor version and accepts community fixes for the one before. |
| [Hugo](https://gohugo.io/about/security/) | Go | Templates and configuration are trusted, content is not, and output is escaped by default. |

## Trusted

An attacker who controls any of these already has what sphinx-argparse-cli could give them:

- The Sphinx configuration and the documents that use the directive.
- The documented project, its modules and the parser factory, which run during the build.

## Untrusted inputs

| Input | Comes from | What sphinx-argparse-cli guarantees |
| ----------------- | -------------------------------------- | -------------------------------------------------------------- |
| Directive options | The `.rst` source of the documentation | Select only which module, function and parser parts to render. |

## Threats and controls

| STRIDE | Threat | Control |
| ---------------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| Tampering | A help string with `.. raw:: html` reaches the HTML. | By design: help text is reStructuredText from trusted code; disable `raw` in Sphinx if contributors are not trusted. |
| Elevation of privilege | Building docs runs the project's code. | Accepted, as in Sphinx autodoc. |

## Release chain

Releases run on the shared [tox-dev/github-workflows](https://github.com/tox-dev/github-workflows) pipeline. A release
App, not a person, pushes the release commit and tag; the build installs its tools from a hash-checked `pylock.toml`
resolved with a seven-day upload cooldown by default; PyPI receives the files through
[trusted publishing](https://docs.pypi.org/trusted-publishers/) with attestations, and the GitHub Release is immutable.
Every workflow pins third-party actions to a commit SHA.

## Vulnerability or bug

| Report | Verdict | Why |
| ------------------------------------------------------ | ------------------- | -------------------------------------- |
| A `:module:` of `a.b` imports `c` instead | Vulnerability | Import target is a guarantee. |
| A help string with `.. raw:: html` adds a script | Not a vulnerability | Help text is trusted reStructuredText. |
| The parser factory deletes files during the docs build | Not a vulnerability | Documented code is trusted. |
| Subcommand order differs from `--help` | Bug | Rendering only. |

## Severity

- **High:** the directive imports a module or calls a function other than the ones its options name.
- **Medium:** the extension reads or writes files beyond the Sphinx build's own outputs.
- **Low:** a crash on an unusual parser instead of a clean build error.

## Accepted risks

- Building documentation executes the documented module's import-time code and parser factory.

## Keeping this current

Revisit this model when sphinx-argparse-cli gains a new input source, network access, a new way to run code, or a new
place it writes to, and whenever an advisory is published.