CORE-1273: migrate from Poetry to uv - #2323
Conversation
Convert pyproject.toml to PEP 621 with the uv_build backend, move dev-requirements.txt into a dev dependency group, commit uv.lock, and switch CI and the Dockerfile to uv. Co-Authored-By: Itamar Hartstein <haritamar@gmail.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
👋 @haritamar |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (4)
📝 WalkthroughWalkthroughThe project migrates from Poetry and pip to uv. Project metadata now uses PEP 621 and Changesuv and packaging migration
Estimated code review effort: 3 (Moderate) | ~20 minutes Mergeability Score: ⚪ Minimal · up to This PR changes the packaging and development tooling while preserving the documented extras and validating builds, tests, and container execution; no actionable merge-blocking risk remains beyond normal checks and review. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Co-Authored-By: Itamar Hartstein <haritamar@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/test-github-action.yml:
- Around line 70-74: Validate inputs.dbt-version before the Install dbt step
constructs package specifications or interpolates it into the shell command.
Reuse the workflow’s existing dbt-version validation mechanism, reject crafted
or unsupported values before installation, and preserve the intended unpinned
behavior when no version is provided.
In `@CONTRIBUTING.md`:
- Around line 19-26: Update the two shell command code fences in the
installation instructions after “Install uv” and “Install the project” to use
the sh language identifier, preserving their existing commands.
In `@pyproject.toml`:
- Around line 71-76: Restore the fabricspark and vertica extras in the published
package metadata and include both adapter extras in the all dependency group.
Update the relevant optional-dependencies and all definitions in pyproject.toml
so elementary-data[fabricspark], elementary-data[vertica], and /app[all]
continue to resolve through the package-extra interface.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1ac971be-bb50-4707-973f-4ea7b03a2056
⛔ Files ignored due to path filters (1)
uv.lockis excluded by!**/*.lock
📒 Files selected for processing (11)
.github/workflows/release.yml.github/workflows/run-precommit.yml.github/workflows/test-github-action.yml.github/workflows/test-warehouse.yml.gitignore.pre-commit-config.yamlCONTRIBUTING.mdDockerfiledev-requirements.txtpoetry.tomlpyproject.toml
💤 Files with no reviewable changes (3)
- poetry.toml
- dev-requirements.txt
- .gitignore
| - name: Install dbt | ||
| run: > | ||
| pip install | ||
| uv pip install | ||
| "dbt-core${{ inputs.dbt-version && format('=={0}', inputs.dbt-version) }}" | ||
| "dbt-snowflake${{ inputs.dbt-version && format('~={0}', inputs.dbt-version) }}" |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the reusable workflow interface and its shell interpolation.
sed -n '1,90p' .github/workflows/test-github-action.yml
# Trace callers and determine whether dbt-version originates from trusted constants,
# validated workflow inputs, or branch-controlled values.
rg -n -C 6 --glob '*.yml' --glob '*.yaml' \
'uses:\s*(\./)?\.github/workflows/test-github-action\.yml|dbt-version:' \
.github/workflowsRepository: elementary-data/elementary
Length of output: 9397
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- test-github-action.yml ---'
sed -n '1,110p' .github/workflows/test-github-action.yml
printf '%s\n' '--- test-warehouse.yml version handling ---'
rg -n -C 10 'dbt-version|pip install|validate|VERSION|^[[:space:]]*on:' \
.github/workflows/test-warehouse.yml
printf '%s\n' '--- all references to test-github-action.yml ---'
rg -n -C 8 --glob '*.yml' --glob '*.yaml' \
'test-github-action\.yml|test-github-action' .github
printf '%s\n' '--- workflow triggers and dispatch inputs ---'
rg -n -C 5 --glob '*.yml' --glob '*.yaml' \
'workflow_dispatch:|pull_request_target:|pull_request:|workflow_call:' .github/workflowsRepository: elementary-data/elementary
Length of output: 16630
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import subprocess
payload = '1.2"; echo INJECTED; #'
command = (
f'uv pip install '
f'"dbt-core=={payload}" '
f'"dbt-snowflake~={payload}"'
)
print('Generated command:')
print(command)
syntax = subprocess.run(
['bash', '-n'],
input=command + '\n',
text=True,
capture_output=True,
)
print(f'bash -n exit code: {syntax.returncode}')
if syntax.stderr:
print(syntax.stderr, end='')
print('Shell command segments:')
print(command.replace(';', '\\n;'))
PYRepository: elementary-data/elementary
Length of output: 416
🌐 Web query:
GitHub Actions workflow_dispatch who can trigger a workflow and access repository secrets permissions
💡 Result:
For GitHub Actions workflows configured with the workflow_dispatch event, here is the breakdown of who can trigger them and how they interact with repository secrets: Who Can Trigger workflow_dispatch By default, any user with write access to the repository can manually trigger a workflow configured with the workflow_dispatch event [1]. As of June 2026, organizations and enterprises can implement more granular control through workflow execution protections [2]. These features allow administrators to define allow lists for specific actors (e.g., specific users, roles such as Maintainer or Admin, or GitHub Apps) and restrict which events are permitted, effectively allowing them to limit manual triggers to specific users or roles [2]. Triggering methods include the GitHub Actions UI, GitHub CLI, or the REST API [1]. For a workflow to be eligible for manual triggering via workflow_dispatch, the workflow file must be present on the default branch [3][1]. Access to Repository Secrets Workflows triggered via workflow_dispatch have access to repository-level secrets [4]. When a workflow runs, it can reference these secrets using the secrets context (e.g., ${{ secrets.MY_SECRET }}) [4]. There are specific conditions where secrets are restricted: - Forked Repositories: Secrets are generally not passed to the runner when a workflow is triggered from a forked repository [5][4]. - Reusable Workflows: If a workflow is called as a reusable workflow (even if it also supports workflow_dispatch), secrets are not automatically passed. They must be explicitly mapped or inherited using the secrets: inherit keyword in the caller workflow [4][6]. - Dependabot: Secrets are not available to workflows triggered by Dependabot events [4]. When triggering a workflow via workflow_dispatch from another workflow (programmatically), the triggering entity must use an authenticated token (such as a Personal Access Token or a GitHub App token) with sufficient permissions—typically actions: write on the target repository [7][8].
Citations:
- 1: https://docs.github.com/en/actions/how-tos/manage-workflow-runs/manually-run-a-workflow?tool=webui
- 2: https://github.blog/changelog/2026-06-18-control-who-and-what-triggers-github-actions-workflows/
- 3: https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/trigger-a-workflow
- 4: https://docs.github.com/actions/security-guides/using-secrets-in-github-actions
- 5: https://docs.github.com/actions/using-workflows/events-that-trigger-workflows
- 6: https://stackoverflow.com/questions/75744243/can-i-dispatch-a-github-reusable-workflow-that-uses-secrets
- 7: https://github.com/step-security/dispatch-workflow
- 8: https://aviitala.com/posts/github-actions-call-another-workflow-via-dispatch/
Validate inputs.dbt-version before shell interpolation. Any user with write access can dispatch this workflow with a crafted value that executes shell commands. The workflow also exposes CI_WAREHOUSE_SECRETS later. Apply the existing dbt-version validation before constructing the package specifications.
🧰 Tools
🪛 zizmor (1.29.0)
[error] 73-73: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
[error] 74-74: code injection via template expansion (template-injection): may expand into attacker-controllable code
(template-injection)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/test-github-action.yml around lines 70 - 74, Validate
inputs.dbt-version before the Install dbt step constructs package specifications
or interpolates it into the shell command. Reuse the workflow’s existing
dbt-version validation mechanism, reject crafted or unsupported values before
installation, and preserve the intended unpinned behavior when no version is
provided.
Source: Linters/SAST tools
There was a problem hiding this comment.
Pre-existing, unchanged by this PR: only pip install -> uv pip install moved on those lines, the inputs.dbt-version interpolation is identical to master. There's no existing validation step in this workflow to reuse, so hardening it is a separate change and out of scope for the Poetry->uv migration.
There was a problem hiding this comment.
Skipped: comment is from another GitHub bot.
| ``` | ||
| python3 -m venv venv | ||
| source venv/bin/activate | ||
| curl -LsSf https://astral.sh/uv/install.sh | sh | ||
| ``` | ||
|
|
||
| #### (3) Install requirements | ||
| #### (3) Install the project | ||
|
|
||
| ``` | ||
| pip install -r dev-requirements.txt | ||
| pip install -e . | ||
| uv sync |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add language identifiers to the shell code fences.
markdownlint-cli2 reports MD040 for both fences. Use sh after each opening fence.
Proposed fix
-```
+```sh
curl -LsSf https://astral.sh/uv/install.sh | sh- +sh
uv sync
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ``` | |
| python3 -m venv venv | |
| source venv/bin/activate | |
| curl -LsSf https://astral.sh/uv/install.sh | sh | |
| ``` | |
| #### (3) Install requirements | |
| #### (3) Install the project | |
| ``` | |
| pip install -r dev-requirements.txt | |
| pip install -e . | |
| uv sync |
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 19-19: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
[warning] 25-25: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CONTRIBUTING.md` around lines 19 - 26, Update the two shell command code
fences in the installation instructions after “Install uv” and “Install the
project” to use the sh language identifier, preserving their existing commands.
Source: Linters/SAST tools
There was a problem hiding this comment.
Skipping: none of the existing fences in CONTRIBUTING.md declare a language, and markdownlint isn't part of the repo's pre-commit config, so adding sh to just these two would be inconsistent.
There was a problem hiding this comment.
Skipped: comment is from another GitHub bot.
Also capitalize [project.urls] labels for PyPI rendering. Co-Authored-By: Itamar Hartstein <haritamar@gmail.com>
Co-Authored-By: Itamar Hartstein <haritamar@gmail.com>
Co-Authored-By: Itamar Hartstein <haritamar@gmail.com>
Summary
Replaces Poetry with uv as the packaging/dev tool.
pyproject.tomlbecomes standard PEP 621 metadata built byuv_build, and dev deps move fromdev-requirements.txtinto a uv dependency group.uv.lockis gitignored, matching the previous Poetry setup wherepoetry.lockwas gitignored too, so resolution stays unpinned.Because the package lives at the repo root rather than in
src/, the build backend needs:Extras (
snowflake,bigquery, ...,all) and theedrscript are unchanged in behavior; theallextra is now expressed as a self-referentialelementary-data[...]list, which is the PEP 621 equivalent of Poetry's extras aggregation.On
constraint-dependencies:urllib3,idna,pyasn1andcryptographyare transitive deps pinned only to dodge CVEs, so moving them to[tool.uv] constraint-dependenciesis tempting — but constraints only affect this project's resolution and are not published in wheel metadata, so anyonepip install elementary-datawould lose the floors. They stay in[project.dependencies].CI/dev surface:
run-precommit:setup-python+ pip →astral-sh/setup-uv+uv sync+uv run pre-commit.test-warehouse/test-github-action:pip install→uv pip install(withUV_SYSTEM_PYTHON=1), dev deps viauv pip install --group dev.release:pip install build+python -m build→uv build --sdist --wheel.Dockerfile: uv0.10.11→0.12.3(it already installed via uv).Verified locally:
uv sync --all-extras, 451 unit tests pass, all pre-commit hooks pass,uv buildartifacts contain theelementarypackage plus the bundled dbt project assets, wheel installs andedr --helpworks, anddocker build+ container run succeed.Link to Devin session: https://app.devin.ai/sessions/c214461411ba46d9ab639b8ea12e69b5
Requested by: @haritamar
Summary by CodeRabbit
Chores
Documentation