dr-environment 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.
- dr_environment-0.1.0/.cursor/BUGBOT.md +67 -0
- dr_environment-0.1.0/.cursor/rules/test-convention.mdc +11 -0
- dr_environment-0.1.0/.github/CODEOWNERS +1 -0
- dr_environment-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +6 -0
- dr_environment-0.1.0/.github/dependabot.yml +33 -0
- dr_environment-0.1.0/.github/pip-audit-ignore.txt +21 -0
- dr_environment-0.1.0/.github/workflows/changelog-check.yml +22 -0
- dr_environment-0.1.0/.github/workflows/ci.yml +183 -0
- dr_environment-0.1.0/.github/workflows/release.yml +108 -0
- dr_environment-0.1.0/.github/workflows/secret-scan.yml +22 -0
- dr_environment-0.1.0/.github/workflows/version-check.yml +72 -0
- dr_environment-0.1.0/.github/workflows/workflow-pr-automation.yaml +66 -0
- dr_environment-0.1.0/.gitignore +217 -0
- dr_environment-0.1.0/.licenserc.yaml +66 -0
- dr_environment-0.1.0/.pre-commit-config.yaml +50 -0
- dr_environment-0.1.0/AGENTS.md +255 -0
- dr_environment-0.1.0/AUTHORS +2 -0
- dr_environment-0.1.0/CHANGELOG.md +36 -0
- dr_environment-0.1.0/CODE_OF_CONDUCT.md +76 -0
- dr_environment-0.1.0/CONTRIBUTING.md +44 -0
- dr_environment-0.1.0/LICENSE +201 -0
- dr_environment-0.1.0/NOTICE +43 -0
- dr_environment-0.1.0/PKG-INFO +216 -0
- dr_environment-0.1.0/PLUGIN_TESTING.md +89 -0
- dr_environment-0.1.0/README.md +182 -0
- dr_environment-0.1.0/SECURITY.md +25 -0
- dr_environment-0.1.0/docs/exec-env.png +0 -0
- dr_environment-0.1.0/docs/img/datarobot_logo.avif +0 -0
- dr_environment-0.1.0/pyproject.toml +98 -0
- dr_environment-0.1.0/src/dr_environment/__init__.py +14 -0
- dr_environment-0.1.0/src/dr_environment/cli.py +91 -0
- dr_environment-0.1.0/src/dr_environment/recipe/__init__.py +19 -0
- dr_environment-0.1.0/src/dr_environment/recipe/build.py +99 -0
- dr_environment-0.1.0/src/dr_environment/recipe/cache/__init__.py +15 -0
- dr_environment-0.1.0/src/dr_environment/recipe/cache/stages.py +151 -0
- dr_environment-0.1.0/src/dr_environment/recipe/discover.py +88 -0
- dr_environment-0.1.0/src/dr_environment/recipe/hooks.py +57 -0
- dr_environment-0.1.0/src/dr_environment/recipe/layout.py +109 -0
- dr_environment-0.1.0/src/dr_environment/recipe/manifests.py +60 -0
- dr_environment-0.1.0/src/dr_environment/recipe/models.py +62 -0
- dr_environment-0.1.0/src/dr_environment/recipe/render.py +139 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/00-base.fragment.j2 +96 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/01-user.fragment.j2 +39 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/02-versions.fragment.j2 +141 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/03-build-deps.fragment.j2 +44 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/04-kernel.fragment.j2 +73 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/99-offline.fragment.j2 +98 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/build-deps/build-requirements.txt +11 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/agent/agent.py +67 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/agent/cgroup_watchers.py +181 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/common-user-limits.sh +38 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/extensions/README.md +2 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/extensions/dataframe_formatter.py +344 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/ipython_config.py +17 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/jupyter_kernel_gateway_config.py +33 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/kernel.json +15 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/notebooks-path.sh +17 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/requirements.txt +8 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/setup-caches.sh +49 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/setup-prompt.sh +20 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/setup-ssh.sh +42 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/setup-venv.sh +97 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/sshd_config +130 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/start_server_codespaces.sh +58 -0
- dr_environment-0.1.0/src/dr_environment/recipe/templates/docker_context/kernel/start_server_custom_model.sh +99 -0
- dr_environment-0.1.0/src/dr_environment/recipe/validate.py +158 -0
- dr_environment-0.1.0/src/dr_environment/recipe/versions.py +82 -0
- dr_environment-0.1.0/tests/__init__.py +15 -0
- dr_environment-0.1.0/tests/recipe/__init__.py +14 -0
- dr_environment-0.1.0/tests/recipe/test_discover.py +67 -0
- dr_environment-0.1.0/tests/recipe/test_layout.py +166 -0
- dr_environment-0.1.0/tests/recipe/test_render.py +270 -0
- dr_environment-0.1.0/tests/recipe/test_stages.py +81 -0
- dr_environment-0.1.0/tests/recipe/test_validate.py +49 -0
- dr_environment-0.1.0/tests/test_cli.py +42 -0
- dr_environment-0.1.0/uv.lock +400 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# BugBot Review Instructions
|
|
2
|
+
|
|
3
|
+
You are a code review bot. When reviewing pull requests in this repository, use the guideline below to identify issues and leave comments.
|
|
4
|
+
|
|
5
|
+
For each violation you detect, leave a comment with a clear title and a message referencing the relevant section of the guideline.
|
|
6
|
+
|
|
7
|
+
Full guideline source: https://datarobot.atlassian.net/wiki/spaces/BUZOK/pages/7305920528/REVIEW+BEFORE+COMMIT+Working+with+agentic+starter+application+and+its+components
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# General guidelines
|
|
12
|
+
|
|
13
|
+
The sections below are the parts of the shared "review before commit" guideline that apply here. The
|
|
14
|
+
sign-off matrix and the template rules in the source cover the agentic starter application and its
|
|
15
|
+
components, not this plugin.
|
|
16
|
+
|
|
17
|
+
### B1. Assume public
|
|
18
|
+
|
|
19
|
+
This repository is public. Therefore:
|
|
20
|
+
|
|
21
|
+
- Do not include internal code, proprietary logic, or private repository references.
|
|
22
|
+
- Avoid leaking internal architecture, infrastructure details, or security mechanisms.
|
|
23
|
+
- Keep comments, README and any other communication language civil, polite, and free of internal references
|
|
24
|
+
|
|
25
|
+
### B2. Update CHANGELOG
|
|
26
|
+
|
|
27
|
+
Use past tense
|
|
28
|
+
|
|
29
|
+
When CHANGELOG.md is present, and your change looks like it should be communicated with users, please add it.
|
|
30
|
+
|
|
31
|
+
Do not add every change: Added .woff2 and .woff and .js files to fastapi_server/static/.gitignore is not important to our users.
|
|
32
|
+
|
|
33
|
+
When bumping child components, list all the changes:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
- Updated agent component from 11.6.3 to 11.6.10:
|
|
37
|
+
- Migrated to a new interface
|
|
38
|
+
- Refactored agent infra concurrency configuration
|
|
39
|
+
- Fixed header forwarding in LangGraph
|
|
40
|
+
- Added debugpy for debugging in IDE
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
# Repo-specific: dr-environment
|
|
46
|
+
|
|
47
|
+
The sections above come from the shared "review before commit" guideline. The following applies
|
|
48
|
+
**only to this repository** (`datarobot-oss/dr-environment`).
|
|
49
|
+
|
|
50
|
+
## Offline and air-gapped builds
|
|
51
|
+
|
|
52
|
+
This plugin renders the execution environment that air-gapped installs build from, so a build step
|
|
53
|
+
that reaches the network at deploy time is a defect rather than a slow path. When reviewing, flag:
|
|
54
|
+
|
|
55
|
+
- A new fetch (`curl`, `pip install`, `uv sync`, `apk add`) in a Dockerfile fragment with no baked
|
|
56
|
+
cache, wheelhouse entry, or find-links source behind it.
|
|
57
|
+
- A fetch inside a command substitution. `$(curl ...)` discards curl's exit status, so a failed
|
|
58
|
+
download still produces a green build and an image missing the tool.
|
|
59
|
+
- Changes to `UV_OFFLINE`, `UV_FROZEN`, `UV_FIND_LINKS`, `UV_PYTHON_PREFERENCE`,
|
|
60
|
+
`NPM_CONFIG_OFFLINE`, or `GOPROXY` with no note on what they break offline.
|
|
61
|
+
|
|
62
|
+
## Pins that ship to customers
|
|
63
|
+
|
|
64
|
+
`versions.yaml`, `kernel/requirements.txt`, and `build-deps/build-requirements.txt` are baked into
|
|
65
|
+
every generated image, so a bump in any of them reaches customer environments and deserves the same
|
|
66
|
+
scrutiny as a runtime dependency. A `versions.yaml` `minimum-version` is interpolated unquoted into
|
|
67
|
+
Dockerfile `ARG` and `RUN` lines, so it must stay a version literal.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
globs: tests/*
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
Follow GIVEN–WHEN–THEN style in tests:
|
|
6
|
+
|
|
7
|
+
- GIVEN: preconditions/state
|
|
8
|
+
- WHEN: the behavior under test
|
|
9
|
+
- THEN: expected outcomes/assertions
|
|
10
|
+
|
|
11
|
+
For background, see Martin Fowler’s article on GivenWhenThen: https://martinfowler.com/bliki/GivenWhenThen.html
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @datarobot-oss/buzok @datarobot-oss/mcp
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "uv"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
open-pull-requests-limit: 5
|
|
8
|
+
labels:
|
|
9
|
+
- "dependencies"
|
|
10
|
+
|
|
11
|
+
- package-ecosystem: "github-actions"
|
|
12
|
+
directory: "/"
|
|
13
|
+
schedule:
|
|
14
|
+
interval: "weekly"
|
|
15
|
+
open-pull-requests-limit: 5
|
|
16
|
+
labels:
|
|
17
|
+
- "dependencies"
|
|
18
|
+
groups:
|
|
19
|
+
actions:
|
|
20
|
+
patterns:
|
|
21
|
+
- "*"
|
|
22
|
+
|
|
23
|
+
# The two pinned manifests baked into every generated image. Dependabot's uv ecosystem
|
|
24
|
+
# does not read bare requirements.txt, so these need their own pip entries.
|
|
25
|
+
- package-ecosystem: "pip"
|
|
26
|
+
directories:
|
|
27
|
+
- "/src/dr_environment/recipe/templates/docker_context/kernel"
|
|
28
|
+
- "/src/dr_environment/recipe/templates/docker_context/build-deps"
|
|
29
|
+
schedule:
|
|
30
|
+
interval: "weekly"
|
|
31
|
+
open-pull-requests-limit: 5
|
|
32
|
+
labels:
|
|
33
|
+
- "dependencies"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Advisory IDs the `audit` CI job skips, one per line. Blank lines and `#` comments ignored.
|
|
2
|
+
#
|
|
3
|
+
# The job fails on any known vulnerability in this project's closure or in either image
|
|
4
|
+
# manifest's resolved closure. Most of those packages are transitive and not pinned here, so an
|
|
5
|
+
# advisory published upstream can turn every open PR red before a fix is available. Listing an ID
|
|
6
|
+
# here unblocks PRs while the bump is worked out; it is not a way to close a finding.
|
|
7
|
+
#
|
|
8
|
+
# Each entry needs the ID, why it is being skipped, and what removes it. Review on every bump.
|
|
9
|
+
#
|
|
10
|
+
# Format:
|
|
11
|
+
# GHSA-xxxx-xxxx-xxxx # <package>: <why skipped> - remove when <condition>
|
|
12
|
+
#
|
|
13
|
+
# Example: pip-audit prints the ID and whether a fix exists:
|
|
14
|
+
#
|
|
15
|
+
# Name Version ID Fix Versions
|
|
16
|
+
# -------- -------- -------------------- ------------
|
|
17
|
+
# urllib3 2.2.1 GHSA-34jh-p97f-mpxf
|
|
18
|
+
#
|
|
19
|
+
# No fix version, and urllib3 is transitive via datarobot, so there is nothing here to bump. Add:
|
|
20
|
+
#
|
|
21
|
+
# GHSA-34jh-p97f-mpxf # urllib3 (transitive via datarobot): no fixed release yet - remove when datarobot pins a fixed urllib3
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: Changelog
|
|
2
|
+
|
|
3
|
+
# Fails a pull request that did not update CHANGELOG.md, bots included: a dependency
|
|
4
|
+
# bump can change what ships. Waivable with the `skip-changelog` label.
|
|
5
|
+
|
|
6
|
+
# `labeled` and `unlabeled` are listed because naming any type replaces the defaults.
|
|
7
|
+
on:
|
|
8
|
+
pull_request:
|
|
9
|
+
types: [opened, synchronize, reopened, labeled, unlabeled]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
changelog:
|
|
16
|
+
uses: datarobot-oss/github-actions/.github/workflows/check-changelog.yaml@0.0.24
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
with:
|
|
20
|
+
changelog_path: CHANGELOG.md
|
|
21
|
+
skip_label: skip-changelog
|
|
22
|
+
skip_bot_authors: false
|
|
@@ -0,0 +1,183 @@
|
|
|
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: ${{ github.event_name == 'pull_request' }}
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
lint:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout
|
|
22
|
+
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
23
|
+
|
|
24
|
+
- name: Set up Python
|
|
25
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
26
|
+
with:
|
|
27
|
+
python-version: '3.12'
|
|
28
|
+
|
|
29
|
+
- name: Install uv
|
|
30
|
+
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
31
|
+
|
|
32
|
+
- name: Cache uv download cache
|
|
33
|
+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
|
34
|
+
with:
|
|
35
|
+
path: ~/.cache/uv
|
|
36
|
+
key: uv-${{ runner.os }}-3.12-${{ hashFiles('uv.lock') }}
|
|
37
|
+
restore-keys: |
|
|
38
|
+
uv-${{ runner.os }}-3.12-
|
|
39
|
+
|
|
40
|
+
- name: Check uv.lock is current
|
|
41
|
+
run: uv lock --check
|
|
42
|
+
|
|
43
|
+
- name: Install dependencies
|
|
44
|
+
run: uv sync --extra dev
|
|
45
|
+
|
|
46
|
+
- name: Lint (ruff format)
|
|
47
|
+
run: uv run ruff format --check src tests
|
|
48
|
+
|
|
49
|
+
- name: Lint (ruff check)
|
|
50
|
+
run: uv run ruff check src tests
|
|
51
|
+
|
|
52
|
+
- name: Type check (mypy)
|
|
53
|
+
run: uv run mypy src
|
|
54
|
+
|
|
55
|
+
test:
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
strategy:
|
|
58
|
+
fail-fast: false
|
|
59
|
+
matrix:
|
|
60
|
+
python-version: [ '3.11', '3.12', '3.13' ]
|
|
61
|
+
permissions:
|
|
62
|
+
contents: read
|
|
63
|
+
steps:
|
|
64
|
+
- name: Checkout
|
|
65
|
+
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
66
|
+
|
|
67
|
+
- name: Set up Python
|
|
68
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
69
|
+
with:
|
|
70
|
+
python-version: ${{ matrix.python-version }}
|
|
71
|
+
|
|
72
|
+
- name: Install uv
|
|
73
|
+
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
74
|
+
|
|
75
|
+
- name: Cache uv download cache
|
|
76
|
+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
|
77
|
+
with:
|
|
78
|
+
path: ~/.cache/uv
|
|
79
|
+
key: uv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('uv.lock') }}
|
|
80
|
+
restore-keys: |
|
|
81
|
+
uv-${{ runner.os }}-${{ matrix.python-version }}-
|
|
82
|
+
|
|
83
|
+
- name: Install dependencies
|
|
84
|
+
run: uv sync --extra dev
|
|
85
|
+
|
|
86
|
+
- name: Run tests
|
|
87
|
+
run: uv run pytest -q --junitxml=test_results/test-results.xml
|
|
88
|
+
|
|
89
|
+
- name: Upload test results
|
|
90
|
+
if: always()
|
|
91
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
92
|
+
with:
|
|
93
|
+
name: junit-py${{ matrix.python-version }}
|
|
94
|
+
path: test_results/test-results.xml
|
|
95
|
+
if-no-files-found: ignore
|
|
96
|
+
|
|
97
|
+
build:
|
|
98
|
+
runs-on: ubuntu-latest
|
|
99
|
+
permissions:
|
|
100
|
+
contents: read
|
|
101
|
+
steps:
|
|
102
|
+
- name: Checkout
|
|
103
|
+
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
104
|
+
|
|
105
|
+
- name: Set up Python
|
|
106
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
107
|
+
with:
|
|
108
|
+
python-version: '3.12'
|
|
109
|
+
|
|
110
|
+
- name: Install uv
|
|
111
|
+
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
112
|
+
|
|
113
|
+
- name: Install dependencies
|
|
114
|
+
run: uv sync --extra dev
|
|
115
|
+
|
|
116
|
+
- name: Build package
|
|
117
|
+
run: uv build
|
|
118
|
+
|
|
119
|
+
- name: Validate package metadata
|
|
120
|
+
run: uvx twine check dist/*
|
|
121
|
+
|
|
122
|
+
- name: Upload dist
|
|
123
|
+
if: always()
|
|
124
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
125
|
+
with:
|
|
126
|
+
name: dist
|
|
127
|
+
path: dist
|
|
128
|
+
if-no-files-found: ignore
|
|
129
|
+
|
|
130
|
+
licenses:
|
|
131
|
+
runs-on: ubuntu-latest
|
|
132
|
+
permissions:
|
|
133
|
+
contents: read
|
|
134
|
+
steps:
|
|
135
|
+
- name: Checkout
|
|
136
|
+
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
137
|
+
|
|
138
|
+
- name: Check copyright headers
|
|
139
|
+
run: |
|
|
140
|
+
docker run --rm -v "$(pwd)":/github/workspace \
|
|
141
|
+
ghcr.io/apache/skywalking-eyes/license-eye:785bb7f3810572d6912666b4f64bad28e4360799 \
|
|
142
|
+
-v info -c .licenserc.yaml header check
|
|
143
|
+
|
|
144
|
+
audit:
|
|
145
|
+
runs-on: ubuntu-latest
|
|
146
|
+
permissions:
|
|
147
|
+
contents: read
|
|
148
|
+
steps:
|
|
149
|
+
- name: Checkout
|
|
150
|
+
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
151
|
+
|
|
152
|
+
- name: Install uv
|
|
153
|
+
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
154
|
+
|
|
155
|
+
# Covers this project's own dependencies and the two pinned manifests that are baked
|
|
156
|
+
# into every generated image, which Dependabot's uv ecosystem cannot read.
|
|
157
|
+
- name: Audit dependencies for known CVEs
|
|
158
|
+
run: |
|
|
159
|
+
# Advisories listed in .github/pip-audit-ignore.txt are skipped, so a CVE with no fix
|
|
160
|
+
# available yet does not block every open PR. That file carries the rationale per entry.
|
|
161
|
+
IDS=()
|
|
162
|
+
while read -r id _; do
|
|
163
|
+
[ -n "$id" ] && IDS+=("$id")
|
|
164
|
+
done < <(sed 's/#.*//' .github/pip-audit-ignore.txt | grep -vE '^[[:space:]]*$')
|
|
165
|
+
IGNORE=()
|
|
166
|
+
for id in "${IDS[@]}"; do IGNORE+=(--ignore-vuln "$id"); done
|
|
167
|
+
echo "Skipping ${#IDS[@]} advisory ID(s) from .github/pip-audit-ignore.txt"
|
|
168
|
+
# uv.lock already resolves this project's full closure, so export and audit directly.
|
|
169
|
+
uv export --frozen --no-hashes --no-dev --no-emit-project -o "${RUNNER_TEMP}/project.txt"
|
|
170
|
+
echo "::group::pip-audit project"
|
|
171
|
+
uvx pip-audit==2.9.0 --disable-pip --no-deps "${IGNORE[@]}" -r "${RUNNER_TEMP}/project.txt"
|
|
172
|
+
echo "::endgroup::"
|
|
173
|
+
# The image manifests list direct pins only, but the build installs their transitive
|
|
174
|
+
# closures. Resolve each against the image's Python before auditing, or CVEs in
|
|
175
|
+
# transitive packages ship without failing CI.
|
|
176
|
+
for f in src/dr_environment/recipe/templates/docker_context/kernel/requirements.txt \
|
|
177
|
+
src/dr_environment/recipe/templates/docker_context/build-deps/build-requirements.txt; do
|
|
178
|
+
resolved="${RUNNER_TEMP}/$(basename "$f").resolved.txt"
|
|
179
|
+
uv pip compile --python-version 3.11 --no-header --no-annotate -o "$resolved" "$f"
|
|
180
|
+
echo "::group::pip-audit $f"
|
|
181
|
+
uvx pip-audit==2.9.0 --disable-pip --no-deps "${IGNORE[@]}" -r "$resolved"
|
|
182
|
+
echo "::endgroup::"
|
|
183
|
+
done
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Tags the version `pyproject.toml` declares and publishes that build to PyPI.
|
|
4
|
+
# Recover a failed publish with "Re-run failed jobs", never "Re-run all jobs": the tag
|
|
5
|
+
# already exists by then, so the publish is skipped rather than retried.
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [ main ]
|
|
9
|
+
|
|
10
|
+
# `cancel-in-progress: false` so a second merge waits, then finds this run's tag. Only one
|
|
11
|
+
# run queues, so a third merge inside one release evicts the second; re-run it on that sha.
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: false
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
# Ahead of the tag: tagging first would strand the version, since an existing tag
|
|
21
|
+
# releases nothing.
|
|
22
|
+
build:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
outputs:
|
|
27
|
+
version: ${{ steps.version.outputs.version }}
|
|
28
|
+
steps:
|
|
29
|
+
- name: Checkout
|
|
30
|
+
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
31
|
+
|
|
32
|
+
- name: Set up Python
|
|
33
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
34
|
+
with:
|
|
35
|
+
python-version: '3.12'
|
|
36
|
+
|
|
37
|
+
- name: Read version from pyproject.toml
|
|
38
|
+
id: version
|
|
39
|
+
uses: datarobot-oss/github-actions/actions/read-pyproject-version@0.0.24
|
|
40
|
+
|
|
41
|
+
- name: Install uv
|
|
42
|
+
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
43
|
+
|
|
44
|
+
- name: Install dependencies
|
|
45
|
+
run: uv sync --extra dev
|
|
46
|
+
|
|
47
|
+
# Gates the publish, not the merge: `ci.yml` covers this commit on its own trigger.
|
|
48
|
+
# Tests only; lint and audit stay there. A release can be yanked, never replaced.
|
|
49
|
+
- name: Run tests
|
|
50
|
+
run: uv run pytest
|
|
51
|
+
|
|
52
|
+
- name: Build package
|
|
53
|
+
run: uv build
|
|
54
|
+
|
|
55
|
+
- name: Validate package metadata
|
|
56
|
+
run: uvx twine check dist/*
|
|
57
|
+
|
|
58
|
+
- name: Upload dist
|
|
59
|
+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
60
|
+
with:
|
|
61
|
+
name: dist
|
|
62
|
+
path: dist
|
|
63
|
+
|
|
64
|
+
release:
|
|
65
|
+
needs: build
|
|
66
|
+
uses: datarobot-oss/github-actions/.github/workflows/create-release-on-merge.yaml@0.0.24
|
|
67
|
+
with:
|
|
68
|
+
version: ${{ needs.build.outputs.version }}
|
|
69
|
+
permissions:
|
|
70
|
+
contents: write
|
|
71
|
+
pull-requests: read
|
|
72
|
+
|
|
73
|
+
# A merge without a bump cuts no tag, so there is nothing to publish.
|
|
74
|
+
publish:
|
|
75
|
+
needs: [ build, release ]
|
|
76
|
+
if: needs.release.outputs.released == 'true'
|
|
77
|
+
runs-on: ubuntu-latest
|
|
78
|
+
# Trusted publishing: PyPI checks this environment claim, so no token is stored.
|
|
79
|
+
environment: pypi
|
|
80
|
+
permissions:
|
|
81
|
+
contents: read
|
|
82
|
+
id-token: write
|
|
83
|
+
steps:
|
|
84
|
+
# The release workflow passes no `target_commitish`, so the tag lands on main's
|
|
85
|
+
# tip, which a merge landing mid-run has already moved. Checked before the upload:
|
|
86
|
+
# a stale tag is deletable, a wheel on PyPI is yank-only.
|
|
87
|
+
- name: Verify the tag is the commit that was built
|
|
88
|
+
env:
|
|
89
|
+
GH_TOKEN: ${{ github.token }}
|
|
90
|
+
TAG: ${{ needs.build.outputs.version }}
|
|
91
|
+
run: |
|
|
92
|
+
TAG_SHA="$(gh api "repos/$GITHUB_REPOSITORY/commits/$TAG" --jq .sha)"
|
|
93
|
+
if [ "$TAG_SHA" != "$GITHUB_SHA" ]; then
|
|
94
|
+
echo "::error::Tag $TAG is $TAG_SHA, not the built $GITHUB_SHA."
|
|
95
|
+
exit 1
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
- name: Download dist
|
|
99
|
+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
|
|
100
|
+
with:
|
|
101
|
+
name: dist
|
|
102
|
+
path: dist
|
|
103
|
+
|
|
104
|
+
- name: Install uv
|
|
105
|
+
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39 # v3
|
|
106
|
+
|
|
107
|
+
- name: Publish to PyPI
|
|
108
|
+
run: uv publish --trusted-publishing always
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: secret-scan
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
pull_request:
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
jobs:
|
|
10
|
+
gitleaks:
|
|
11
|
+
name: "gitleaks"
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
15
|
+
with:
|
|
16
|
+
fetch-depth: 0
|
|
17
|
+
|
|
18
|
+
- name: gitleaks
|
|
19
|
+
run: |
|
|
20
|
+
docker run --rm -v "$(pwd)":/repo -w /repo \
|
|
21
|
+
ghcr.io/gitleaks/gitleaks:v8.29.1 \
|
|
22
|
+
detect --source=/repo --redact --verbose --no-banner
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: Version
|
|
2
|
+
|
|
3
|
+
# A merge releases the version `pyproject.toml` declares, so a pull request that changes
|
|
4
|
+
# what ships has to bump it. Waivable with the `skip-version-bump` label.
|
|
5
|
+
|
|
6
|
+
# `labeled` and `unlabeled` are listed because naming any type replaces the defaults.
|
|
7
|
+
on:
|
|
8
|
+
pull_request:
|
|
9
|
+
types: [opened, synchronize, reopened, labeled, unlabeled]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
version:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
steps:
|
|
20
|
+
- name: Checkout
|
|
21
|
+
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
22
|
+
with:
|
|
23
|
+
# Full history, for the base branch's pyproject.toml.
|
|
24
|
+
fetch-depth: 0
|
|
25
|
+
|
|
26
|
+
- name: Require a version bump when what ships changes
|
|
27
|
+
env:
|
|
28
|
+
BASE: origin/${{ github.base_ref }}
|
|
29
|
+
SKIP: ${{ contains(github.event.pull_request.labels.*.name, 'skip-version-bump') }}
|
|
30
|
+
run: |
|
|
31
|
+
set -euo pipefail
|
|
32
|
+
|
|
33
|
+
# In the step, not a job-level `if`: branch protection counts a skipped job as
|
|
34
|
+
# passing, so the waiver has to run and report rather than skip.
|
|
35
|
+
if [ "$SKIP" = 'true' ]; then
|
|
36
|
+
echo "Waived by skip-version-bump."
|
|
37
|
+
exit 0
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Paths that reach a consumer; `pyproject.toml` because its metadata ships in METADATA.
|
|
41
|
+
CHANGED="$(git -c core.quotePath=false diff --name-only --no-renames "${BASE}...HEAD")"
|
|
42
|
+
if ! grep -qE '^(src/|pyproject\.toml$|README\.md$|LICENSE$|NOTICE$|AUTHORS$)' <<<"$CHANGED"; then
|
|
43
|
+
echo "Nothing that ships changed."
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# Parsed, not grepped: `version` appears in other tables and spacing around `=` varies.
|
|
48
|
+
read_version() {
|
|
49
|
+
git show "$1:pyproject.toml" \
|
|
50
|
+
| python3 -c 'import sys, tomllib; print(tomllib.load(sys.stdin.buffer)["project"]["version"])'
|
|
51
|
+
}
|
|
52
|
+
BASE_VERSION="$(read_version "$BASE")"
|
|
53
|
+
HEAD_VERSION="$(read_version HEAD)"
|
|
54
|
+
|
|
55
|
+
if [ "$BASE_VERSION" = "$HEAD_VERSION" ]; then
|
|
56
|
+
echo "::error::pyproject.toml still declares $BASE_VERSION. Bump it, or apply skip-version-bump."
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
# Checked here, not at release time: a bad version would otherwise redden main.
|
|
61
|
+
if ! printf '%s' "$HEAD_VERSION" | grep -qE '^(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*)){2}$'; then
|
|
62
|
+
echo "::error::'$HEAD_VERSION' is not a plain X.Y.Z; the build backend strips leading zeros."
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
LATEST="$(printf '%s\n%s\n' "$BASE_VERSION" "$HEAD_VERSION" | sort -V | tail -1)"
|
|
67
|
+
if [ "$LATEST" != "$HEAD_VERSION" ]; then
|
|
68
|
+
echo "::error::pyproject.toml goes backwards, from $BASE_VERSION to $HEAD_VERSION."
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
echo "Version bumped from $BASE_VERSION to $HEAD_VERSION."
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: PR Automation
|
|
2
|
+
|
|
3
|
+
# Reviewer-facing helpers: labels approved pull requests `00 - Reviewed`, comments a
|
|
4
|
+
# Jira link, and posts to Slack. Both Slack jobs need `SLACK_WEBHOOK_URL`.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
pull_request_review:
|
|
8
|
+
types: [submitted]
|
|
9
|
+
pull_request:
|
|
10
|
+
types: [opened, edited, labeled]
|
|
11
|
+
schedule:
|
|
12
|
+
- cron: '0 * * * *'
|
|
13
|
+
workflow_dispatch:
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
# On an approving review: label the PR "00 - Reviewed".
|
|
20
|
+
mark-reviewed:
|
|
21
|
+
if: github.event_name == 'pull_request_review' && github.event.review.state == 'approved'
|
|
22
|
+
uses: datarobot-oss/github-actions/.github/workflows/mark-pr-reviewed.yaml@0.0.24
|
|
23
|
+
with:
|
|
24
|
+
pr_number: ${{ github.event.pull_request.number }}
|
|
25
|
+
permissions:
|
|
26
|
+
pull-requests: write
|
|
27
|
+
|
|
28
|
+
# On the `00 - Ready for Review` label: announce the pull request in Slack.
|
|
29
|
+
notify-ready-for-review:
|
|
30
|
+
if: github.event_name == 'pull_request' && github.event.action == 'labeled' && github.event.label.name == '00 - Ready for Review'
|
|
31
|
+
uses: datarobot-oss/github-actions/.github/workflows/mark-pr-to-review.yaml@0.0.24
|
|
32
|
+
with:
|
|
33
|
+
pr_number: ${{ github.event.pull_request.number }}
|
|
34
|
+
pr_url: ${{ github.event.pull_request.html_url }}
|
|
35
|
+
pr_title: ${{ github.event.pull_request.title }}
|
|
36
|
+
pr_author: ${{ github.event.pull_request.user.login }}
|
|
37
|
+
pr_additions: ${{ github.event.pull_request.additions }}
|
|
38
|
+
pr_deletions: ${{ github.event.pull_request.deletions }}
|
|
39
|
+
repo_name: ${{ github.repository }}
|
|
40
|
+
secrets:
|
|
41
|
+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
42
|
+
permissions:
|
|
43
|
+
pull-requests: write
|
|
44
|
+
|
|
45
|
+
# On PR open/edit: comment a link to any Jira ticket in the title or branch.
|
|
46
|
+
add-jira-link:
|
|
47
|
+
if: github.event_name == 'pull_request' && (github.event.action == 'opened' || github.event.action == 'edited')
|
|
48
|
+
uses: datarobot-oss/github-actions/.github/workflows/add-jira-link.yaml@0.0.24
|
|
49
|
+
with:
|
|
50
|
+
jira_base_url: 'https://datarobot.atlassian.net/browse'
|
|
51
|
+
pr_title: ${{ github.event.pull_request.title }}
|
|
52
|
+
pr_number: ${{ github.event.pull_request.number }}
|
|
53
|
+
pr_branch: ${{ github.head_ref }}
|
|
54
|
+
permissions:
|
|
55
|
+
pull-requests: write
|
|
56
|
+
|
|
57
|
+
# On schedule or dispatch: post a digest of what is still awaiting review.
|
|
58
|
+
notify-slack-digest:
|
|
59
|
+
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
|
|
60
|
+
uses: datarobot-oss/github-actions/.github/workflows/notify-slack.yaml@0.0.24
|
|
61
|
+
secrets:
|
|
62
|
+
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
63
|
+
permissions:
|
|
64
|
+
contents: read
|
|
65
|
+
pull-requests: write
|
|
66
|
+
statuses: read
|