gestate 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gestate-1.0.0/.github/workflows/docs.yml +39 -0
- gestate-1.0.0/.github/workflows/release.yml +29 -0
- gestate-1.0.0/.gitignore +18 -0
- gestate-1.0.0/LICENSE +21 -0
- gestate-1.0.0/PKG-INFO +89 -0
- gestate-1.0.0/README.md +67 -0
- gestate-1.0.0/RELEASE.md +38 -0
- gestate-1.0.0/docs/allowlists.md +65 -0
- gestate-1.0.0/docs/complementary.md +64 -0
- gestate-1.0.0/docs/index.md +37 -0
- gestate-1.0.0/pyproject.toml +43 -0
- gestate-1.0.0/src/gestate/__init__.py +3 -0
- gestate-1.0.0/src/gestate/__main__.py +3 -0
- gestate-1.0.0/src/gestate/cli.py +713 -0
- gestate-1.0.0/src/gestate/config.py +135 -0
- gestate-1.0.0/src/gestate/detect.py +60 -0
- gestate-1.0.0/src/gestate/status.py +68 -0
- gestate-1.0.0/tests/test_cli.py +161 -0
- gestate-1.0.0/tests/test_config.py +235 -0
- gestate-1.0.0/tests/test_status.py +64 -0
- gestate-1.0.0/uv.lock +406 -0
- gestate-1.0.0/zensical.toml +47 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pages: write
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: pages
|
|
15
|
+
cancel-in-progress: false
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
build:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: astral-sh/setup-uv@v6
|
|
23
|
+
with:
|
|
24
|
+
enable-cache: true
|
|
25
|
+
- run: uv sync --group docs --frozen
|
|
26
|
+
- run: uv run zensical build
|
|
27
|
+
- uses: actions/upload-pages-artifact@v3
|
|
28
|
+
with:
|
|
29
|
+
path: site
|
|
30
|
+
|
|
31
|
+
deploy:
|
|
32
|
+
needs: build
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
environment:
|
|
35
|
+
name: github-pages
|
|
36
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/deploy-pages@v4
|
|
39
|
+
id: deployment
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
- uses: astral-sh/setup-uv@v6
|
|
14
|
+
with:
|
|
15
|
+
enable-cache: true
|
|
16
|
+
- run: uv sync --frozen
|
|
17
|
+
- run: uv run pytest
|
|
18
|
+
|
|
19
|
+
publish:
|
|
20
|
+
needs: test
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
environment: pypi
|
|
23
|
+
permissions:
|
|
24
|
+
id-token: write
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v4
|
|
27
|
+
- uses: astral-sh/setup-uv@v6
|
|
28
|
+
- run: uv build
|
|
29
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
gestate-1.0.0/.gitignore
ADDED
gestate-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lincoln Loop
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
gestate-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: gestate
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Set a minimum release age on local package managers to defend against zero-day supply chain attacks.
|
|
5
|
+
Author-email: Lincoln Loop <chris@lincolnloop.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: bun,cooldown,deno,npm,pip,pnpm,security,supply-chain,uv,yarn
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: System Administrators
|
|
13
|
+
Classifier: Operating System :: MacOS
|
|
14
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
15
|
+
Classifier: Topic :: Security
|
|
16
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
17
|
+
Classifier: Topic :: System :: Installation/Setup
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Requires-Dist: rich>=13
|
|
20
|
+
Requires-Dist: tomli-w>=1.0
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# gestate
|
|
24
|
+
|
|
25
|
+
Set a minimum release age on local package managers so installs ignore versions younger than `N` days. Most malicious packages are caught and yanked within days of publishing; refusing fresh versions blocks the bulk of supply-chain attacks.
|
|
26
|
+
|
|
27
|
+
## Run
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
uvx gestate # interactive
|
|
31
|
+
uvx gestate set 3 # 3-day minimum, installed tools only
|
|
32
|
+
uvx gestate set 3 --all # also pre-configure file-based tools (bun, deno, uv)
|
|
33
|
+
uvx gestate revert # remove gestate's settings
|
|
34
|
+
uvx gestate explain bun # show how one tool's setting is stored
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Interactive mode always shows a plan and asks for explicit confirmation before touching anything. The subcommands skip the confirm — meant for scripts, not your daily shell. Running with no subcommand outside a TTY exits with an error.
|
|
38
|
+
|
|
39
|
+
Plain text output is used when stdout isn't a terminal (no Rich tables/colors).
|
|
40
|
+
|
|
41
|
+
## What it sets
|
|
42
|
+
|
|
43
|
+
| Tool | Where | Key (unit) |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| npm | `~/.npmrc` | `min-release-age` (days) |
|
|
46
|
+
| pnpm | global pnpm config | `minimumReleaseAge` (minutes) |
|
|
47
|
+
| yarn | `~/.yarnrc.yml` (4.10+) | `npmMinimalAgeGate` (minutes) |
|
|
48
|
+
| bun | `~/.bunfig.toml` | `[install] minimumReleaseAge` (seconds) |
|
|
49
|
+
| deno | shell profile | `alias deno='command deno --minimum-dependency-age=P<N>D'` |
|
|
50
|
+
| pip | user pip config | `global.uploaded-prior-to` (`P<N>D`) |
|
|
51
|
+
| uv | `~/.config/uv/uv.toml` | `exclude-newer` (`"N days"`) |
|
|
52
|
+
|
|
53
|
+
`gestate explain <tool>` prints that tool's current value and the exact mechanism `set` / `revert` use.
|
|
54
|
+
|
|
55
|
+
Scope:
|
|
56
|
+
- default — only configure installed tools
|
|
57
|
+
- `--all` — also pre-write config files for `bun`, `deno`, `uv` even if they aren't installed yet
|
|
58
|
+
|
|
59
|
+
## Revert
|
|
60
|
+
|
|
61
|
+
`uvx gestate revert` removes everything gestate set:
|
|
62
|
+
|
|
63
|
+
- CLI tools — `config delete` / `config unset`
|
|
64
|
+
- `bun` / `uv` — remove the key; delete the file if it was the only key
|
|
65
|
+
- `deno` — remove our alias line; leave foreign `alias deno=` lines alone
|
|
66
|
+
|
|
67
|
+
Backups (`.bak`) are written next to any edited shell-profile or TOML file.
|
|
68
|
+
|
|
69
|
+
## Allowlists
|
|
70
|
+
|
|
71
|
+
If you publish packages of your own and want them exempt from the delay, see [docs/allowlists.md](docs/allowlists.md). Most managers support an exclude list; npm and pip don't yet.
|
|
72
|
+
|
|
73
|
+
## Caveats
|
|
74
|
+
|
|
75
|
+
- **yarn**: 4.10+ only. Older yarn is detected and skipped.
|
|
76
|
+
- **deno**: no global config exists; the shell alias only covers interactive shells. For CI, pass `--minimum-dependency-age=P<N>D` to `deno install`/`deno update`, or commit a project `deno.json` with `"minimumDependencyAge": "P<N>D"`.
|
|
77
|
+
- **npm exclude**: tracked in [npm/cli#8994](https://github.com/npm/cli/issues/8994).
|
|
78
|
+
- **pip exclude**: none — `global.uploaded-prior-to` is global only.
|
|
79
|
+
|
|
80
|
+
For PR-creation guards (Dependabot, Renovate) and adjacent layers, see [docs/complementary.md](docs/complementary.md).
|
|
81
|
+
|
|
82
|
+
## Development
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
uv sync
|
|
86
|
+
uv run pytest
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Requires Python 3.11+, macOS or Linux.
|
gestate-1.0.0/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# gestate
|
|
2
|
+
|
|
3
|
+
Set a minimum release age on local package managers so installs ignore versions younger than `N` days. Most malicious packages are caught and yanked within days of publishing; refusing fresh versions blocks the bulk of supply-chain attacks.
|
|
4
|
+
|
|
5
|
+
## Run
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
uvx gestate # interactive
|
|
9
|
+
uvx gestate set 3 # 3-day minimum, installed tools only
|
|
10
|
+
uvx gestate set 3 --all # also pre-configure file-based tools (bun, deno, uv)
|
|
11
|
+
uvx gestate revert # remove gestate's settings
|
|
12
|
+
uvx gestate explain bun # show how one tool's setting is stored
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Interactive mode always shows a plan and asks for explicit confirmation before touching anything. The subcommands skip the confirm — meant for scripts, not your daily shell. Running with no subcommand outside a TTY exits with an error.
|
|
16
|
+
|
|
17
|
+
Plain text output is used when stdout isn't a terminal (no Rich tables/colors).
|
|
18
|
+
|
|
19
|
+
## What it sets
|
|
20
|
+
|
|
21
|
+
| Tool | Where | Key (unit) |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| npm | `~/.npmrc` | `min-release-age` (days) |
|
|
24
|
+
| pnpm | global pnpm config | `minimumReleaseAge` (minutes) |
|
|
25
|
+
| yarn | `~/.yarnrc.yml` (4.10+) | `npmMinimalAgeGate` (minutes) |
|
|
26
|
+
| bun | `~/.bunfig.toml` | `[install] minimumReleaseAge` (seconds) |
|
|
27
|
+
| deno | shell profile | `alias deno='command deno --minimum-dependency-age=P<N>D'` |
|
|
28
|
+
| pip | user pip config | `global.uploaded-prior-to` (`P<N>D`) |
|
|
29
|
+
| uv | `~/.config/uv/uv.toml` | `exclude-newer` (`"N days"`) |
|
|
30
|
+
|
|
31
|
+
`gestate explain <tool>` prints that tool's current value and the exact mechanism `set` / `revert` use.
|
|
32
|
+
|
|
33
|
+
Scope:
|
|
34
|
+
- default — only configure installed tools
|
|
35
|
+
- `--all` — also pre-write config files for `bun`, `deno`, `uv` even if they aren't installed yet
|
|
36
|
+
|
|
37
|
+
## Revert
|
|
38
|
+
|
|
39
|
+
`uvx gestate revert` removes everything gestate set:
|
|
40
|
+
|
|
41
|
+
- CLI tools — `config delete` / `config unset`
|
|
42
|
+
- `bun` / `uv` — remove the key; delete the file if it was the only key
|
|
43
|
+
- `deno` — remove our alias line; leave foreign `alias deno=` lines alone
|
|
44
|
+
|
|
45
|
+
Backups (`.bak`) are written next to any edited shell-profile or TOML file.
|
|
46
|
+
|
|
47
|
+
## Allowlists
|
|
48
|
+
|
|
49
|
+
If you publish packages of your own and want them exempt from the delay, see [docs/allowlists.md](docs/allowlists.md). Most managers support an exclude list; npm and pip don't yet.
|
|
50
|
+
|
|
51
|
+
## Caveats
|
|
52
|
+
|
|
53
|
+
- **yarn**: 4.10+ only. Older yarn is detected and skipped.
|
|
54
|
+
- **deno**: no global config exists; the shell alias only covers interactive shells. For CI, pass `--minimum-dependency-age=P<N>D` to `deno install`/`deno update`, or commit a project `deno.json` with `"minimumDependencyAge": "P<N>D"`.
|
|
55
|
+
- **npm exclude**: tracked in [npm/cli#8994](https://github.com/npm/cli/issues/8994).
|
|
56
|
+
- **pip exclude**: none — `global.uploaded-prior-to` is global only.
|
|
57
|
+
|
|
58
|
+
For PR-creation guards (Dependabot, Renovate) and adjacent layers, see [docs/complementary.md](docs/complementary.md).
|
|
59
|
+
|
|
60
|
+
## Development
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
uv sync
|
|
64
|
+
uv run pytest
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Requires Python 3.11+, macOS or Linux.
|
gestate-1.0.0/RELEASE.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Releasing
|
|
2
|
+
|
|
3
|
+
## Publishing to PyPI
|
|
4
|
+
|
|
5
|
+
Requires PyPI credentials in your keyring (see below).
|
|
6
|
+
|
|
7
|
+
Tag the current release and push it:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git pull
|
|
11
|
+
git tag --list "v*"
|
|
12
|
+
git tag -a vX.Y.Z -m "Release vX.Y.Z"
|
|
13
|
+
git push --tags
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Build and publish:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
rm -rf dist
|
|
20
|
+
uv build
|
|
21
|
+
uv publish
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## PyPI Credentials Setup
|
|
25
|
+
|
|
26
|
+
Install keyring (used by uv for publishing) and set your token:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uv tool install keyring
|
|
30
|
+
keyring set 'https://upload.pypi.org/legacy/' __token__
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Add these environment variables to your shell:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
export UV_KEYRING_PROVIDER=subprocess
|
|
37
|
+
export UV_PUBLISH_USERNAME=__token__
|
|
38
|
+
```
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Allowlists
|
|
2
|
+
|
|
3
|
+
Each manager (where supported) lets you exempt specific packages from the release-age delay. Useful for your own org's packages and trusted hotfixes.
|
|
4
|
+
|
|
5
|
+
## bun — `minimumReleaseAgeExcludes`
|
|
6
|
+
|
|
7
|
+
`~/.bunfig.toml`:
|
|
8
|
+
|
|
9
|
+
```toml
|
|
10
|
+
[install]
|
|
11
|
+
minimumReleaseAge = 604800
|
|
12
|
+
minimumReleaseAgeExcludes = ["@myorg/*", "typescript"]
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Globs allowed. Matches every version of the package.
|
|
16
|
+
|
|
17
|
+
## yarn — `npmPreapprovedPackages`
|
|
18
|
+
|
|
19
|
+
`~/.yarnrc.yml`:
|
|
20
|
+
|
|
21
|
+
```yaml
|
|
22
|
+
npmMinimalAgeGate: 10080
|
|
23
|
+
npmPreapprovedPackages:
|
|
24
|
+
- "@myorg/*"
|
|
25
|
+
- "@aws-sdk/types@3.877.0"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Globs or exact `name@version` locators.
|
|
29
|
+
|
|
30
|
+
## pnpm — `minimumReleaseAgeExclude`
|
|
31
|
+
|
|
32
|
+
`pnpm-workspace.yaml` (or `.npmrc` with kebab-case keys):
|
|
33
|
+
|
|
34
|
+
```yaml
|
|
35
|
+
minimumReleaseAge: 10080
|
|
36
|
+
minimumReleaseAgeExclude:
|
|
37
|
+
- '@myorg/*'
|
|
38
|
+
- nx@21.6.5
|
|
39
|
+
- 'webpack@4.47.0 || 5.102.1'
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Package name, glob, or `name@version-range`.
|
|
43
|
+
|
|
44
|
+
## uv — `exclude-newer-package`
|
|
45
|
+
|
|
46
|
+
`pyproject.toml`:
|
|
47
|
+
|
|
48
|
+
```toml
|
|
49
|
+
[tool.uv]
|
|
50
|
+
exclude-newer-package = { requests = "ALLOW_ANY", setuptools = "30 days" }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`ALLOW_ANY` bypasses the cooldown for that package; a duration string applies a different window.
|
|
54
|
+
|
|
55
|
+
## npm — not shipped
|
|
56
|
+
|
|
57
|
+
Tracked in [npm/cli#8994](https://github.com/npm/cli/issues/8994). Until then, `min-release-age` is global only.
|
|
58
|
+
|
|
59
|
+
## pip — no equivalent
|
|
60
|
+
|
|
61
|
+
`global.uploaded-prior-to` is global. Pinning a specific newer version in `requirements.txt` is the workaround.
|
|
62
|
+
|
|
63
|
+
## deno — no equivalent
|
|
64
|
+
|
|
65
|
+
`--minimum-dependency-age` is global per invocation.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Complementary Controls
|
|
2
|
+
|
|
3
|
+
`gestate` guards the **install** step. Pair it with controls at other layers for defense in depth.
|
|
4
|
+
|
|
5
|
+
## PR-creation layer
|
|
6
|
+
|
|
7
|
+
Stop bump PRs from landing fresh versions in the first place.
|
|
8
|
+
|
|
9
|
+
### Dependabot cooldown (GitHub-native)
|
|
10
|
+
|
|
11
|
+
Added July 2025. Configured per ecosystem in `.github/dependabot.yml`:
|
|
12
|
+
|
|
13
|
+
```yaml
|
|
14
|
+
version: 2
|
|
15
|
+
updates:
|
|
16
|
+
- package-ecosystem: npm
|
|
17
|
+
directory: /
|
|
18
|
+
schedule:
|
|
19
|
+
interval: daily
|
|
20
|
+
cooldown:
|
|
21
|
+
default-days: 7
|
|
22
|
+
semver-major-days: 14
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Supported on all Dependabot ecosystems. Different cooldowns per semver bump type are allowed.
|
|
26
|
+
|
|
27
|
+
See: <https://github.blog/changelog/2025-07-01-dependabot-supports-configuration-of-a-minimum-package-age/>
|
|
28
|
+
|
|
29
|
+
### Renovate `minimumReleaseAge`
|
|
30
|
+
|
|
31
|
+
Renovate has shipped this for years. Set in `renovate.json`:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"minimumReleaseAge": "7 days"
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Applies to all managers Renovate supports (npm, pip, cargo, gomod, etc.).
|
|
40
|
+
|
|
41
|
+
## Install-script layer
|
|
42
|
+
|
|
43
|
+
Most supply-chain payloads execute via `postinstall` / `preinstall` hooks. Disable them unless explicitly needed.
|
|
44
|
+
|
|
45
|
+
- **npm**: `npm config set ignore-scripts true` (global). Allow per-package via dedicated trusted lists.
|
|
46
|
+
- **pnpm**: `onlyBuiltDependencies` in `package.json` — explicit allowlist for which packages may run install scripts.
|
|
47
|
+
- **bun**: `trustedDependencies` in `package.json`.
|
|
48
|
+
|
|
49
|
+
## Lockfile + provenance layer
|
|
50
|
+
|
|
51
|
+
- **Lockfiles committed**: `package-lock.json`, `pnpm-lock.yaml`, `bun.lock`, `uv.lock` — pin exact resolved versions so a malicious republish under the same range can't slip in silently.
|
|
52
|
+
- **npm provenance**: `npm publish --provenance` ties published artifacts to a verifiable CI build. Consumers can check `npm view <pkg> --json` for the `dist.attestations` field.
|
|
53
|
+
- **Sigstore / SLSA**: same idea, broader ecosystem coverage.
|
|
54
|
+
|
|
55
|
+
## Layer summary
|
|
56
|
+
|
|
57
|
+
| Layer | Tool | Catches |
|
|
58
|
+
|-------|------|---------|
|
|
59
|
+
| PR creation | Dependabot cooldown, Renovate `minimumReleaseAge` | Bump PRs for fresh versions |
|
|
60
|
+
| Install resolution | `gestate` (this repo) | Direct + transitive + ad-hoc installs, CI without bots |
|
|
61
|
+
| Install scripts | `ignore-scripts`, `onlyBuiltDependencies`, `trustedDependencies` | Lifecycle-hook payloads |
|
|
62
|
+
| Identity | Lockfiles, provenance, Sigstore | Republish / typosquat / impersonation |
|
|
63
|
+
|
|
64
|
+
No single layer is sufficient. The install-time guard in this repo is the broadest net; the others narrow specific attack paths.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
icon: lucide/shield-check
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# gestate
|
|
6
|
+
|
|
7
|
+
Set a minimum release age on local package managers so installs ignore versions younger than `N` days. Most malicious packages are caught and yanked within days of publishing; refusing fresh versions blocks the bulk of supply-chain attacks.
|
|
8
|
+
|
|
9
|
+
## Run
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
uvx gestate # interactive
|
|
13
|
+
uvx gestate set 3 # 3-day minimum, installed tools only
|
|
14
|
+
uvx gestate set 3 --all # also pre-configure file-based tools (bun, deno, uv)
|
|
15
|
+
uvx gestate revert # remove gestate's settings
|
|
16
|
+
uvx gestate explain bun # show how one tool's setting is stored
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Interactive mode always shows a plan and asks for confirmation before touching anything. The subcommands skip the confirm — meant for scripts, not your daily shell.
|
|
20
|
+
|
|
21
|
+
## What it configures
|
|
22
|
+
|
|
23
|
+
| Tool | Where | Key (unit) |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| npm | `~/.npmrc` | `min-release-age` (days) |
|
|
26
|
+
| pnpm | global pnpm config | `minimumReleaseAge` (minutes) |
|
|
27
|
+
| yarn | `~/.yarnrc.yml` (4.10+) | `npmMinimalAgeGate` (minutes) |
|
|
28
|
+
| bun | `~/.bunfig.toml` | `[install] minimumReleaseAge` (seconds) |
|
|
29
|
+
| deno | shell profile | `alias deno='command deno --minimum-dependency-age=P<N>D'` |
|
|
30
|
+
| pip | user pip config | `global.uploaded-prior-to` (`P<N>D`) |
|
|
31
|
+
| uv | `~/.config/uv/uv.toml` | `exclude-newer` (`"N days"`) |
|
|
32
|
+
|
|
33
|
+
## More
|
|
34
|
+
|
|
35
|
+
- [Allowlists](allowlists.md) — exempt your own packages from the delay
|
|
36
|
+
- [Complementary controls](complementary.md) — pair gestate with PR-creation guards and other defense layers
|
|
37
|
+
- [Source on GitHub](https://github.com/lincolnloop/gestate)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "gestate"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Set a minimum release age on local package managers to defend against zero-day supply chain attacks."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [{ name = "Lincoln Loop", email = "chris@lincolnloop.com" }]
|
|
10
|
+
keywords = ["supply-chain", "security", "cooldown", "npm", "pip", "uv", "pnpm", "bun", "yarn", "deno"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Intended Audience :: System Administrators",
|
|
16
|
+
"Topic :: Security",
|
|
17
|
+
"Topic :: Software Development :: Build Tools",
|
|
18
|
+
"Topic :: System :: Installation/Setup",
|
|
19
|
+
"Operating System :: MacOS",
|
|
20
|
+
"Operating System :: POSIX :: Linux",
|
|
21
|
+
]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"rich>=13",
|
|
24
|
+
"tomli-w>=1.0",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.scripts]
|
|
28
|
+
gestate = "gestate.cli:main"
|
|
29
|
+
|
|
30
|
+
[dependency-groups]
|
|
31
|
+
dev = ["pytest>=8"]
|
|
32
|
+
docs = ["zensical>=0.0.43"]
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
requires = ["hatchling"]
|
|
36
|
+
build-backend = "hatchling.build"
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.wheel]
|
|
39
|
+
packages = ["src/gestate"]
|
|
40
|
+
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
testpaths = ["tests"]
|
|
43
|
+
addopts = "-q"
|