Metadata-Version: 2.4
Name: cooldown-guard
Version: 0.1.1
Summary: auditable uv cooldown exceptions for emergency dependency upgrades
Project-URL: homepage, https://github.com/ischemist/cooldown-guard
Project-URL: repository, https://github.com/ischemist/cooldown-guard
Project-URL: issues, https://github.com/ischemist/cooldown-guard/issues
Keywords: dependencies,python,security,supply-chain,uv
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Build Tools
Requires-Python: >=3.11
Requires-Dist: httpx>=0.27
Requires-Dist: packaging>=24.0
Requires-Dist: pydantic>=2.7
Requires-Dist: tomlkit>=0.13
Requires-Dist: typer>=0.12
Description-Content-Type: text/markdown

# cooldown-guard

`cooldown-guard` makes `uv` cooldown exceptions auditable, narrow, and easy to clean up.

it is built around four ideas:

- keep global `exclude-newer` on
- allow temporary package-specific exceptions for emergency fixes
- pin the exception with `constraint-dependencies`
- automatically relax the exception once the normal cooldown window catches up

## what it writes

given a project like:

```toml
[tool.uv]
exclude-newer = "7 days"
```

an approval like:

```bash
cooldown-guard approve urllib3==2.7.0 \
  --project /path/to/repo \
  --approved-by alice \
  --reason "security fix" \
  --advisory CVE-2026-12345 \
  --introduced-via requests \
  --introduced-via types-tqdm
```

will update the target `pyproject.toml` to look like:

```toml
[tool.uv]
exclude-newer = "7 days"
exclude-newer-package = { urllib3 = "2026-05-07T16:13:18Z" }
constraint-dependencies = ["urllib3==2.7.0"]
```

and create a `.cooldown-guard.toml` ledger beside it.

## commands

- `cooldown-guard approve <package>==<version>`: add a narrow exception and run `uv lock`
- `cooldown-guard validate`: verify that the ledger and `pyproject.toml` agree
- `cooldown-guard status`: show active and cleaned exceptions
- `cooldown-guard cleanup --check`: test whether an active exception can now be relaxed from `==` to `>=`
- `cooldown-guard cleanup --apply`: apply that relaxation and run `uv lock`

## ci

the repo includes:

- [.github/workflows/ci.yml](/Users/morgunov/Developer/ischemist/dev-tools/cooldown-guard/.github/workflows/ci.yml): tests the tool itself
- [.github/workflows/release-drafter.yml](/Users/morgunov/Developer/ischemist/dev-tools/cooldown-guard/.github/workflows/release-drafter.yml): labels prs from conventional commits and maintains a draft github release
- [examples/github-actions/validate.yml](/Users/morgunov/Developer/ischemist/dev-tools/cooldown-guard/examples/github-actions/validate.yml): consumer-side validation on pull requests
- [examples/github-actions/reconcile.yml](/Users/morgunov/Developer/ischemist/dev-tools/cooldown-guard/examples/github-actions/reconcile.yml): nightly cleanup that can open a pull request

the example workflows install `cooldown-guard` directly from pypi and pin the tool version with `COOLDOWN_GUARD_VERSION` for reproducibility.

## release flow

- release drafts are maintained by [release-drafter](/Users/morgunov/Developer/ischemist/dev-tools/cooldown-guard/.github/release-drafter.yml)
- pypi publish happens from [.github/workflows/publish-pypi.yml](/Users/morgunov/Developer/ischemist/dev-tools/cooldown-guard/.github/workflows/publish-pypi.yml) using github oidc trusted publishing
- the publish workflow refuses to run unless the github release tag matches `v<project.version>` from `pyproject.toml`

for pypi trusted publisher setup, register:

- owner: `ischemist`
- repository: `cooldown-guard`
- workflow: `publish-pypi.yml`
- environment: `pypi`

## notes

- `approved_by` is audit metadata, not authorization. real authorization should still come from codeowners, branch protection, and normal review policy.
- the tool shells out to `uv lock` instead of reimplementing resolution.
- v1 intentionally targets the common case where the repo-level `exclude-newer` is a duration like `"7 days"`.
