dep-rank 0.1.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.
- dep_rank-0.1.0/.github/CODEOWNERS +2 -0
- dep_rank-0.1.0/.github/actions/setup-uv/README.md +18 -0
- dep_rank-0.1.0/.github/actions/setup-uv/action.yml +19 -0
- dep_rank-0.1.0/.github/dependabot.yml +36 -0
- dep_rank-0.1.0/.github/workflows/ci.yml +159 -0
- dep_rank-0.1.0/.github/workflows/dependency-cooldown-rescan.yml +23 -0
- dep_rank-0.1.0/.github/workflows/dependency-cooldown.yml +22 -0
- dep_rank-0.1.0/.github/workflows/pre-commit-autoupdate.yml +55 -0
- dep_rank-0.1.0/.github/workflows/release.yml +192 -0
- dep_rank-0.1.0/.github/workflows/security.yml +160 -0
- dep_rank-0.1.0/.github/workflows/tag-release.yml +27 -0
- dep_rank-0.1.0/.gitignore +11 -0
- dep_rank-0.1.0/.pre-commit-config.yaml +12 -0
- dep_rank-0.1.0/.python-version +1 -0
- dep_rank-0.1.0/Dockerfile +23 -0
- dep_rank-0.1.0/LICENSE +22 -0
- dep_rank-0.1.0/PKG-INFO +201 -0
- dep_rank-0.1.0/README.md +171 -0
- dep_rank-0.1.0/RELEASE.md +119 -0
- dep_rank-0.1.0/main.py +4 -0
- dep_rank-0.1.0/pyproject.toml +121 -0
- dep_rank-0.1.0/pytest.ini +21 -0
- dep_rank-0.1.0/setup.cfg +8 -0
- dep_rank-0.1.0/src/dep_rank/__init__.py +5 -0
- dep_rank-0.1.0/src/dep_rank/_version.py +24 -0
- dep_rank-0.1.0/src/dep_rank/cli/__init__.py +1 -0
- dep_rank-0.1.0/src/dep_rank/cli/app.py +370 -0
- dep_rank-0.1.0/src/dep_rank/cli/formatters.py +92 -0
- dep_rank-0.1.0/src/dep_rank/core/__init__.py +31 -0
- dep_rank-0.1.0/src/dep_rank/core/cache.py +92 -0
- dep_rank-0.1.0/src/dep_rank/core/graphql.py +87 -0
- dep_rank-0.1.0/src/dep_rank/core/models.py +64 -0
- dep_rank-0.1.0/src/dep_rank/core/rate_limiter.py +41 -0
- dep_rank-0.1.0/src/dep_rank/core/scraper.py +319 -0
- dep_rank-0.1.0/src/dep_rank/core/search.py +79 -0
- dep_rank-0.1.0/src/dep_rank/core/validation.py +74 -0
- dep_rank-0.1.0/src/dep_rank/mcp/__init__.py +1 -0
- dep_rank-0.1.0/src/dep_rank/mcp/server.py +262 -0
- dep_rank-0.1.0/tests/README.md +135 -0
- dep_rank-0.1.0/tests/__init__.py +0 -0
- dep_rank-0.1.0/tests/cli/__init__.py +0 -0
- dep_rank-0.1.0/tests/cli/test_commands.py +288 -0
- dep_rank-0.1.0/tests/cli/test_formatters.py +170 -0
- dep_rank-0.1.0/tests/conftest.py +185 -0
- dep_rank-0.1.0/tests/core/__init__.py +0 -0
- dep_rank-0.1.0/tests/core/test_cache.py +108 -0
- dep_rank-0.1.0/tests/core/test_graphql.py +128 -0
- dep_rank-0.1.0/tests/core/test_models.py +127 -0
- dep_rank-0.1.0/tests/core/test_rate_limiter.py +39 -0
- dep_rank-0.1.0/tests/core/test_scraper.py +492 -0
- dep_rank-0.1.0/tests/core/test_search.py +112 -0
- dep_rank-0.1.0/tests/core/test_validation.py +89 -0
- dep_rank-0.1.0/tests/mcp/__init__.py +0 -0
- dep_rank-0.1.0/tests/mcp/test_lifecycle.py +16 -0
- dep_rank-0.1.0/tests/mcp/test_prompts.py +26 -0
- dep_rank-0.1.0/tests/mcp/test_tools.py +246 -0
- dep_rank-0.1.0/uv.lock +2632 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# setup-uv composite action
|
|
2
|
+
|
|
3
|
+
Installs uv with dependency caching and runs `uv sync --locked` to install
|
|
4
|
+
the project environment. Used by jobs that need a synced dev environment
|
|
5
|
+
to run tests, linters, type-checkers, or `uv build`.
|
|
6
|
+
|
|
7
|
+
## Inputs
|
|
8
|
+
|
|
9
|
+
| Name | Default | Description |
|
|
10
|
+
| ---------------- | ------- | ------------------------------------ |
|
|
11
|
+
| `python-version` | `3.11` | Python version to install and use. |
|
|
12
|
+
|
|
13
|
+
## When NOT to use this action
|
|
14
|
+
|
|
15
|
+
Skip this action and call `astral-sh/setup-uv` inline for jobs that:
|
|
16
|
+
|
|
17
|
+
- Mutate the lockfile (`uv lock`) — `--locked` would fail on drift.
|
|
18
|
+
- Don't need the project environment synced (e.g., `pre-commit autoupdate`).
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: Setup uv
|
|
2
|
+
description: Install uv with dependency caching and sync the project env (--locked).
|
|
3
|
+
inputs:
|
|
4
|
+
python-version:
|
|
5
|
+
description: "Python version to install"
|
|
6
|
+
required: false
|
|
7
|
+
default: "3.11"
|
|
8
|
+
runs:
|
|
9
|
+
using: "composite"
|
|
10
|
+
steps:
|
|
11
|
+
- name: Install uv
|
|
12
|
+
uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 # v8.0.0
|
|
13
|
+
with:
|
|
14
|
+
enable-cache: true
|
|
15
|
+
cache-dependency-glob: "uv.lock"
|
|
16
|
+
python-version: ${{ inputs.python-version }}
|
|
17
|
+
- name: Sync dependencies (locked)
|
|
18
|
+
run: uv sync --locked
|
|
19
|
+
shell: bash
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# Python dependencies via uv
|
|
4
|
+
- package-ecosystem: "uv"
|
|
5
|
+
directory: "/"
|
|
6
|
+
schedule:
|
|
7
|
+
interval: "weekly"
|
|
8
|
+
day: "monday"
|
|
9
|
+
time: "09:00"
|
|
10
|
+
open-pull-requests-limit: 10
|
|
11
|
+
labels:
|
|
12
|
+
- "dependencies"
|
|
13
|
+
- "automated"
|
|
14
|
+
commit-message:
|
|
15
|
+
prefix: "deps"
|
|
16
|
+
include: "scope"
|
|
17
|
+
groups:
|
|
18
|
+
minor-and-patch:
|
|
19
|
+
patterns: ["*"]
|
|
20
|
+
update-types: ["minor", "patch"]
|
|
21
|
+
ignore:
|
|
22
|
+
- dependency-name: "*"
|
|
23
|
+
update-types: ["version-update:semver-major"]
|
|
24
|
+
|
|
25
|
+
# GitHub Actions
|
|
26
|
+
- package-ecosystem: "github-actions"
|
|
27
|
+
directory: "/"
|
|
28
|
+
schedule:
|
|
29
|
+
interval: "weekly"
|
|
30
|
+
labels:
|
|
31
|
+
- "dependencies"
|
|
32
|
+
- "github-actions"
|
|
33
|
+
groups:
|
|
34
|
+
all-actions:
|
|
35
|
+
patterns:
|
|
36
|
+
- "*"
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
permissions: {}
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
update-lockfile:
|
|
16
|
+
if: github.event.pull_request.user.login == 'dependabot[bot]'
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
outputs:
|
|
19
|
+
committed: ${{ steps.commit.outputs.committed }}
|
|
20
|
+
permissions:
|
|
21
|
+
contents: read
|
|
22
|
+
steps:
|
|
23
|
+
- name: Harden runner
|
|
24
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
25
|
+
with:
|
|
26
|
+
egress-policy: audit
|
|
27
|
+
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
|
|
28
|
+
id: app-token
|
|
29
|
+
with:
|
|
30
|
+
client-id: ${{ vars.RELEASE_BOT_APP_ID }}
|
|
31
|
+
private-key: ${{ secrets.RELEASE_BOT_PRIVATE_KEY }}
|
|
32
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
33
|
+
with:
|
|
34
|
+
ref: ${{ github.head_ref }}
|
|
35
|
+
persist-credentials: false
|
|
36
|
+
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
37
|
+
- run: uv lock
|
|
38
|
+
- name: Commit updated lockfile
|
|
39
|
+
id: commit
|
|
40
|
+
env:
|
|
41
|
+
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
|
42
|
+
HEAD_REF: ${{ github.head_ref }}
|
|
43
|
+
REPOSITORY: ${{ github.repository }}
|
|
44
|
+
run: |
|
|
45
|
+
if git diff --quiet uv.lock; then
|
|
46
|
+
echo "No lockfile changes"
|
|
47
|
+
echo "committed=false" >> "$GITHUB_OUTPUT"
|
|
48
|
+
exit 0
|
|
49
|
+
fi
|
|
50
|
+
CONTENT=$(base64 -w0 uv.lock)
|
|
51
|
+
HEAD_OID=$(git rev-parse HEAD)
|
|
52
|
+
# shellcheck disable=SC2016
|
|
53
|
+
gh api graphql -f query='
|
|
54
|
+
mutation($input: CreateCommitOnBranchInput!) {
|
|
55
|
+
createCommitOnBranch(input: $input) {
|
|
56
|
+
commit { url }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
' -f "input[branchRef][repositoryNameWithOwner]=$REPOSITORY" \
|
|
60
|
+
-f "input[branchRef][branchName]=$HEAD_REF" \
|
|
61
|
+
-f "input[expectedHeadOid]=${HEAD_OID}" \
|
|
62
|
+
-f "input[message][headline]=deps: update uv.lock" \
|
|
63
|
+
-f "input[fileChanges][additions][0][path]=uv.lock" \
|
|
64
|
+
-f "input[fileChanges][additions][0][contents]=${CONTENT}"
|
|
65
|
+
echo "committed=true" >> "$GITHUB_OUTPUT"
|
|
66
|
+
|
|
67
|
+
lint:
|
|
68
|
+
needs: [update-lockfile]
|
|
69
|
+
if: ${{ !cancelled() }}
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
permissions:
|
|
72
|
+
contents: read
|
|
73
|
+
steps:
|
|
74
|
+
- name: Harden runner
|
|
75
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
76
|
+
with:
|
|
77
|
+
egress-policy: audit
|
|
78
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
79
|
+
with:
|
|
80
|
+
ref: ${{ needs.update-lockfile.outputs.committed == 'true' && github.head_ref || '' }}
|
|
81
|
+
persist-credentials: false
|
|
82
|
+
- uses: ./.github/actions/setup-uv
|
|
83
|
+
- name: Ruff format check
|
|
84
|
+
run: uv run ruff format --check src/ tests/
|
|
85
|
+
- name: Ruff check
|
|
86
|
+
run: uv run ruff check src/ tests/
|
|
87
|
+
|
|
88
|
+
typecheck:
|
|
89
|
+
needs: [update-lockfile]
|
|
90
|
+
if: ${{ !cancelled() }}
|
|
91
|
+
runs-on: ubuntu-latest
|
|
92
|
+
permissions:
|
|
93
|
+
contents: read
|
|
94
|
+
steps:
|
|
95
|
+
- name: Harden runner
|
|
96
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
97
|
+
with:
|
|
98
|
+
egress-policy: audit
|
|
99
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
100
|
+
with:
|
|
101
|
+
ref: ${{ needs.update-lockfile.outputs.committed == 'true' && github.head_ref || '' }}
|
|
102
|
+
persist-credentials: false
|
|
103
|
+
- uses: ./.github/actions/setup-uv
|
|
104
|
+
- name: Mypy
|
|
105
|
+
run: uv run mypy src/dep_rank/
|
|
106
|
+
|
|
107
|
+
test:
|
|
108
|
+
needs: [update-lockfile]
|
|
109
|
+
if: ${{ !cancelled() }}
|
|
110
|
+
strategy:
|
|
111
|
+
fail-fast: false
|
|
112
|
+
matrix:
|
|
113
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
114
|
+
python-version: ['3.11', '3.12', '3.13']
|
|
115
|
+
runs-on: ${{ matrix.os }}
|
|
116
|
+
permissions:
|
|
117
|
+
contents: read
|
|
118
|
+
steps:
|
|
119
|
+
- name: Harden runner
|
|
120
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
121
|
+
with:
|
|
122
|
+
egress-policy: audit
|
|
123
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
124
|
+
with:
|
|
125
|
+
ref: ${{ needs.update-lockfile.outputs.committed == 'true' && github.head_ref || '' }}
|
|
126
|
+
persist-credentials: false
|
|
127
|
+
fetch-depth: 0
|
|
128
|
+
- uses: ./.github/actions/setup-uv
|
|
129
|
+
with:
|
|
130
|
+
python-version: ${{ matrix.python-version }}
|
|
131
|
+
- name: Pytest
|
|
132
|
+
run: uv run pytest
|
|
133
|
+
- name: Diff coverage
|
|
134
|
+
if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11'
|
|
135
|
+
env:
|
|
136
|
+
BASE_REF: ${{ github.base_ref }}
|
|
137
|
+
run: uv run diff-cover coverage.xml --fail-under=80 --compare-branch="origin/$BASE_REF"
|
|
138
|
+
|
|
139
|
+
dependency-review:
|
|
140
|
+
runs-on: ubuntu-latest
|
|
141
|
+
if: github.event_name == 'pull_request'
|
|
142
|
+
permissions:
|
|
143
|
+
contents: read
|
|
144
|
+
pull-requests: write
|
|
145
|
+
steps:
|
|
146
|
+
- name: Harden runner
|
|
147
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
148
|
+
with:
|
|
149
|
+
egress-policy: audit
|
|
150
|
+
- name: Checkout code
|
|
151
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
152
|
+
|
|
153
|
+
- name: Dependency Review
|
|
154
|
+
uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0
|
|
155
|
+
with:
|
|
156
|
+
fail-on-severity: moderate
|
|
157
|
+
deny-licenses: GPL-2.0, GPL-3.0, AGPL-3.0
|
|
158
|
+
allow-dependencies-licenses: pkg:githubactions/trufflesecurity/trufflehog
|
|
159
|
+
comment-summary-in-pr: on-failure
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
name: Dependency Cool-Down Rescan
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: "17 6 * * *"
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
dry_run:
|
|
9
|
+
description: "If true, log decisions but skip gh run rerun"
|
|
10
|
+
type: boolean
|
|
11
|
+
default: false
|
|
12
|
+
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
pull-requests: read
|
|
16
|
+
actions: write
|
|
17
|
+
statuses: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
rescan:
|
|
21
|
+
uses: j7an/shared-workflows/.github/workflows/cooldown-rescan.yml@365119edbe2b1c7339d7727d9e8d021784e5bc01 # v2.5.2
|
|
22
|
+
with:
|
|
23
|
+
dry_run: ${{ inputs.dry_run || false }}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Dependency Cool-Down
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, synchronize, reopened]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
pull-requests: write
|
|
10
|
+
statuses: write
|
|
11
|
+
issues: write
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: cooldown-${{ github.event.pull_request.number }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
cooldown:
|
|
19
|
+
uses: j7an/shared-workflows/.github/workflows/dependency-cooldown.yml@365119edbe2b1c7339d7727d9e8d021784e5bc01 # v2.5.2
|
|
20
|
+
with:
|
|
21
|
+
auto_merge: true
|
|
22
|
+
cooldown_days: 5
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Pre-commit Autoupdate
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
- cron: "0 8 * * 1" # Monday 08:00 UTC
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions: {}
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
autoupdate:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
steps:
|
|
16
|
+
- name: Harden runner
|
|
17
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
18
|
+
with:
|
|
19
|
+
egress-policy: audit
|
|
20
|
+
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
|
|
21
|
+
id: app-token
|
|
22
|
+
with:
|
|
23
|
+
client-id: ${{ vars.RELEASE_BOT_APP_ID }}
|
|
24
|
+
private-key: ${{ secrets.RELEASE_BOT_PRIVATE_KEY }}
|
|
25
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
26
|
+
with:
|
|
27
|
+
persist-credentials: false
|
|
28
|
+
- uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
29
|
+
- name: Install pre-commit
|
|
30
|
+
run: uv run pre-commit --version
|
|
31
|
+
- name: Run pre-commit autoupdate
|
|
32
|
+
run: uv run pre-commit autoupdate
|
|
33
|
+
- name: Check for changes
|
|
34
|
+
id: diff
|
|
35
|
+
run: |
|
|
36
|
+
if git diff --quiet .pre-commit-config.yaml; then
|
|
37
|
+
echo "changed=false" >> "$GITHUB_OUTPUT"
|
|
38
|
+
else
|
|
39
|
+
echo "changed=true" >> "$GITHUB_OUTPUT"
|
|
40
|
+
fi
|
|
41
|
+
- name: Create Pull Request
|
|
42
|
+
if: steps.diff.outputs.changed == 'true'
|
|
43
|
+
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
|
|
44
|
+
with:
|
|
45
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
46
|
+
branch: deps/pre-commit-autoupdate
|
|
47
|
+
title: "deps: update pre-commit hooks"
|
|
48
|
+
commit-message: "deps: update pre-commit hooks"
|
|
49
|
+
sign-commits: true
|
|
50
|
+
add-paths: .pre-commit-config.yaml
|
|
51
|
+
body: |
|
|
52
|
+
Automated update of pre-commit hook versions via `pre-commit autoupdate`.
|
|
53
|
+
|
|
54
|
+
Review the diff to verify hook version changes are expected.
|
|
55
|
+
labels: dependencies
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
name: CI gate
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Harden runner
|
|
17
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
18
|
+
with:
|
|
19
|
+
egress-policy: audit
|
|
20
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
21
|
+
with:
|
|
22
|
+
fetch-depth: 0
|
|
23
|
+
- uses: ./.github/actions/setup-uv
|
|
24
|
+
- run: uv run ruff check src/ tests/
|
|
25
|
+
- run: uv run mypy src/dep_rank/
|
|
26
|
+
- run: uv run pytest
|
|
27
|
+
|
|
28
|
+
build:
|
|
29
|
+
name: Build distributions
|
|
30
|
+
needs: test
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
steps:
|
|
33
|
+
- name: Harden runner
|
|
34
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
35
|
+
with:
|
|
36
|
+
egress-policy: audit
|
|
37
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
38
|
+
with:
|
|
39
|
+
fetch-depth: 0
|
|
40
|
+
fetch-tags: true
|
|
41
|
+
|
|
42
|
+
- name: Verify tag is on main
|
|
43
|
+
run: |
|
|
44
|
+
git fetch origin main
|
|
45
|
+
if ! git merge-base --is-ancestor ${{ github.sha }} origin/main; then
|
|
46
|
+
echo "ERROR: Tagged commit $(git rev-parse --short HEAD) is not on main"
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
- uses: ./.github/actions/setup-uv
|
|
51
|
+
|
|
52
|
+
- name: Build sdist and wheel
|
|
53
|
+
run: uv build
|
|
54
|
+
|
|
55
|
+
- name: Verify distributions
|
|
56
|
+
run: |
|
|
57
|
+
ls -la dist/
|
|
58
|
+
WHEEL=$(ls dist/*.whl 2>/dev/null | wc -l)
|
|
59
|
+
SDIST=$(ls dist/*.tar.gz 2>/dev/null | wc -l)
|
|
60
|
+
if [ "$WHEEL" -eq 0 ] || [ "$SDIST" -eq 0 ]; then
|
|
61
|
+
echo "ERROR: Expected both a wheel and sdist in dist/"
|
|
62
|
+
ls dist/
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
echo "Build produced: $(ls dist/)"
|
|
66
|
+
|
|
67
|
+
- name: Upload build artifacts
|
|
68
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
69
|
+
with:
|
|
70
|
+
name: dist
|
|
71
|
+
path: dist/
|
|
72
|
+
retention-days: 7
|
|
73
|
+
|
|
74
|
+
publish-testpypi:
|
|
75
|
+
name: Publish to TestPyPI
|
|
76
|
+
needs: build
|
|
77
|
+
runs-on: ubuntu-latest
|
|
78
|
+
environment:
|
|
79
|
+
name: testpypi
|
|
80
|
+
url: https://test.pypi.org/p/dep-rank
|
|
81
|
+
permissions:
|
|
82
|
+
id-token: write
|
|
83
|
+
attestations: write
|
|
84
|
+
steps:
|
|
85
|
+
- name: Harden runner
|
|
86
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
87
|
+
with:
|
|
88
|
+
egress-policy: audit
|
|
89
|
+
- name: Download build artifacts
|
|
90
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
91
|
+
with:
|
|
92
|
+
name: dist
|
|
93
|
+
path: dist/
|
|
94
|
+
|
|
95
|
+
- name: Publish to TestPyPI
|
|
96
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
|
|
97
|
+
with:
|
|
98
|
+
repository-url: https://test.pypi.org/legacy/
|
|
99
|
+
skip-existing: true
|
|
100
|
+
|
|
101
|
+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
|
102
|
+
with:
|
|
103
|
+
python-version: "3.13"
|
|
104
|
+
|
|
105
|
+
- name: Verify TestPyPI install
|
|
106
|
+
run: |
|
|
107
|
+
VERSION="${GITHUB_REF_NAME#v}"
|
|
108
|
+
echo "Waiting for dep-rank==${VERSION} to appear on TestPyPI..."
|
|
109
|
+
for i in 1 2 3 4 5; do
|
|
110
|
+
sleep $((i * 30))
|
|
111
|
+
if pip install \
|
|
112
|
+
--index-url https://test.pypi.org/simple/ \
|
|
113
|
+
--extra-index-url https://pypi.org/simple/ \
|
|
114
|
+
"dep-rank==${VERSION}" 2>/dev/null; then
|
|
115
|
+
ACTUAL=$(dep-rank --version 2>&1)
|
|
116
|
+
echo "Installed version: ${ACTUAL}"
|
|
117
|
+
echo "${ACTUAL}" | grep -qF "${VERSION}" || {
|
|
118
|
+
echo "ERROR: Expected '${VERSION}' in dep-rank --version output"
|
|
119
|
+
exit 1
|
|
120
|
+
}
|
|
121
|
+
echo "TestPyPI install OK"
|
|
122
|
+
exit 0
|
|
123
|
+
fi
|
|
124
|
+
echo "Attempt $i: not yet available, retrying..."
|
|
125
|
+
done
|
|
126
|
+
echo "ERROR: dep-rank==${VERSION} not available on TestPyPI after 7.5 minutes"
|
|
127
|
+
exit 1
|
|
128
|
+
|
|
129
|
+
publish-pypi:
|
|
130
|
+
name: Publish to PyPI
|
|
131
|
+
needs: [build, publish-testpypi]
|
|
132
|
+
runs-on: ubuntu-latest
|
|
133
|
+
environment:
|
|
134
|
+
name: pypi
|
|
135
|
+
url: https://pypi.org/p/dep-rank
|
|
136
|
+
permissions:
|
|
137
|
+
id-token: write
|
|
138
|
+
attestations: write
|
|
139
|
+
steps:
|
|
140
|
+
- name: Harden runner
|
|
141
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
142
|
+
with:
|
|
143
|
+
egress-policy: audit
|
|
144
|
+
- name: Download build artifacts
|
|
145
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
146
|
+
with:
|
|
147
|
+
name: dist
|
|
148
|
+
path: dist/
|
|
149
|
+
|
|
150
|
+
- name: Publish to PyPI
|
|
151
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
|
|
152
|
+
|
|
153
|
+
github-release:
|
|
154
|
+
name: Create GitHub Release
|
|
155
|
+
needs: [build, publish-pypi]
|
|
156
|
+
if: needs.publish-pypi.result == 'success'
|
|
157
|
+
runs-on: ubuntu-latest
|
|
158
|
+
permissions:
|
|
159
|
+
contents: write
|
|
160
|
+
steps:
|
|
161
|
+
- name: Harden runner
|
|
162
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
163
|
+
with:
|
|
164
|
+
egress-policy: audit
|
|
165
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
166
|
+
with:
|
|
167
|
+
fetch-depth: 0
|
|
168
|
+
|
|
169
|
+
- name: Download build artifacts
|
|
170
|
+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
171
|
+
with:
|
|
172
|
+
name: dist
|
|
173
|
+
path: dist/
|
|
174
|
+
|
|
175
|
+
- name: Classify tag (stable vs prerelease)
|
|
176
|
+
id: classify
|
|
177
|
+
env:
|
|
178
|
+
REF: ${{ github.ref_name }}
|
|
179
|
+
run: |
|
|
180
|
+
if [[ "$REF" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(\.post[0-9]+)?$ ]]; then
|
|
181
|
+
echo "prerelease=false" >> "$GITHUB_OUTPUT"
|
|
182
|
+
else
|
|
183
|
+
echo "prerelease=true" >> "$GITHUB_OUTPUT"
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
- name: Create GitHub Release with assets
|
|
187
|
+
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
|
188
|
+
with:
|
|
189
|
+
generate_release_notes: true
|
|
190
|
+
draft: true
|
|
191
|
+
prerelease: ${{ steps.classify.outputs.prerelease }}
|
|
192
|
+
files: dist/*
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
name: Security Scanning
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
merge_group:
|
|
9
|
+
branches: [main]
|
|
10
|
+
schedule:
|
|
11
|
+
- cron: "0 6 * * 1" # Weekly Monday 06:00 UTC
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
permissions: {}
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
codeql:
|
|
21
|
+
name: CodeQL
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
permissions:
|
|
24
|
+
contents: read
|
|
25
|
+
security-events: write
|
|
26
|
+
actions: read
|
|
27
|
+
steps:
|
|
28
|
+
- name: Harden runner
|
|
29
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
30
|
+
with:
|
|
31
|
+
egress-policy: audit
|
|
32
|
+
|
|
33
|
+
- name: Checkout repository
|
|
34
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
35
|
+
|
|
36
|
+
- name: Initialize CodeQL
|
|
37
|
+
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
|
|
38
|
+
with:
|
|
39
|
+
languages: python
|
|
40
|
+
queries: +security-and-quality
|
|
41
|
+
|
|
42
|
+
- name: Perform CodeQL Analysis
|
|
43
|
+
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
|
|
44
|
+
with:
|
|
45
|
+
category: "/language:python"
|
|
46
|
+
|
|
47
|
+
trufflehog:
|
|
48
|
+
name: TruffleHog
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
permissions:
|
|
51
|
+
contents: read
|
|
52
|
+
steps:
|
|
53
|
+
- name: Harden runner
|
|
54
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
55
|
+
with:
|
|
56
|
+
egress-policy: audit
|
|
57
|
+
|
|
58
|
+
- name: Checkout repository
|
|
59
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
60
|
+
with:
|
|
61
|
+
fetch-depth: 0
|
|
62
|
+
|
|
63
|
+
- name: TruffleHog secret scan
|
|
64
|
+
id: trufflehog
|
|
65
|
+
uses: trufflesecurity/trufflehog@17456f8c7d042d8c82c9a8ca9e937231f9f42e26 # v3.95.2
|
|
66
|
+
continue-on-error: true
|
|
67
|
+
with:
|
|
68
|
+
path: ./
|
|
69
|
+
base: ${{ github.event.pull_request.base.sha || github.event.before }}
|
|
70
|
+
head: ${{ github.event.pull_request.head.sha || github.event.after }}
|
|
71
|
+
extra_args: --only-verified
|
|
72
|
+
|
|
73
|
+
- name: Fail on verified secrets
|
|
74
|
+
if: steps.trufflehog.outcome == 'failure'
|
|
75
|
+
run: |
|
|
76
|
+
echo "::error::TruffleHog detected verified secrets. Review the scan output above."
|
|
77
|
+
exit 1
|
|
78
|
+
|
|
79
|
+
zizmor:
|
|
80
|
+
name: Zizmor
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
permissions:
|
|
83
|
+
contents: read
|
|
84
|
+
security-events: write
|
|
85
|
+
steps:
|
|
86
|
+
- name: Harden runner
|
|
87
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
88
|
+
with:
|
|
89
|
+
egress-policy: audit
|
|
90
|
+
|
|
91
|
+
- name: Checkout repository
|
|
92
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
93
|
+
with:
|
|
94
|
+
persist-credentials: false
|
|
95
|
+
|
|
96
|
+
- name: Run Zizmor
|
|
97
|
+
uses: zizmorcore/zizmor-action@b1d7e1fb5de872772f31590499237e7cce841e8e # v0.5.3
|
|
98
|
+
with:
|
|
99
|
+
version: "1.24.1"
|
|
100
|
+
min-severity: medium
|
|
101
|
+
min-confidence: medium
|
|
102
|
+
|
|
103
|
+
trivy:
|
|
104
|
+
name: Trivy
|
|
105
|
+
runs-on: ubuntu-latest
|
|
106
|
+
permissions:
|
|
107
|
+
contents: read
|
|
108
|
+
security-events: write
|
|
109
|
+
steps:
|
|
110
|
+
- name: Harden runner
|
|
111
|
+
uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 # v2.19.0
|
|
112
|
+
with:
|
|
113
|
+
egress-policy: audit
|
|
114
|
+
|
|
115
|
+
- name: Checkout repository
|
|
116
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
117
|
+
|
|
118
|
+
- name: Generate SARIF report
|
|
119
|
+
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
|
120
|
+
with:
|
|
121
|
+
scan-type: repo
|
|
122
|
+
format: sarif
|
|
123
|
+
output: trivy-results.sarif
|
|
124
|
+
|
|
125
|
+
- name: Upload Trivy results to GitHub Security tab
|
|
126
|
+
if: always()
|
|
127
|
+
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
|
|
128
|
+
with:
|
|
129
|
+
sarif_file: trivy-results.sarif
|
|
130
|
+
category: trivy
|
|
131
|
+
|
|
132
|
+
- name: Fail on CRITICAL/HIGH vulnerabilities
|
|
133
|
+
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
|
134
|
+
with:
|
|
135
|
+
scan-type: repo
|
|
136
|
+
format: table
|
|
137
|
+
severity: CRITICAL,HIGH
|
|
138
|
+
exit-code: "1"
|
|
139
|
+
|
|
140
|
+
osv-scan:
|
|
141
|
+
name: OSV-Scanner
|
|
142
|
+
if: github.event_name == 'push' || github.event_name == 'schedule'
|
|
143
|
+
permissions:
|
|
144
|
+
actions: read
|
|
145
|
+
contents: read
|
|
146
|
+
security-events: write
|
|
147
|
+
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@c51854704019a247608d928f370c98740469d4b5 # v2.3.5
|
|
148
|
+
with:
|
|
149
|
+
scan-args: --recursive ./
|
|
150
|
+
|
|
151
|
+
osv-scan-pr:
|
|
152
|
+
name: OSV-Scanner PR
|
|
153
|
+
if: github.event_name == 'pull_request' || github.event_name == 'merge_group'
|
|
154
|
+
permissions:
|
|
155
|
+
actions: read
|
|
156
|
+
contents: read
|
|
157
|
+
security-events: write
|
|
158
|
+
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable-pr.yml@c51854704019a247608d928f370c98740469d4b5 # v2.3.5
|
|
159
|
+
with:
|
|
160
|
+
scan-args: --recursive ./
|