Skip to content

BUILD-11568 Add config-uv action - #293

Merged
hedinasr merged 1 commit into
masterfrom
feat/hnasr/BUILD-11568-createConfigUv
Jun 25, 2026
Merged

BUILD-11568 Add config-uv action#293
hedinasr merged 1 commit into
masterfrom
feat/hnasr/BUILD-11568-createConfigUv

Conversation

@hedinasr

@hedinasr hedinasr commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add config-uv composite action to fetch Artifactory reader credentials from Vault and expose UV_INDEX_* authentication for the Repox PyPI index
  • Cache uv dependencies under .cache/uv keyed on uv.lock and pyproject.toml
  • Add shellspec coverage and README documentation

Test plan

  • shellspec spec/config-uv_spec.sh passes locally (5 examples)
  • Pre-commit hooks pass (yamllint, shellcheck, markdownlint)
  • CI shellspec workflow passes
  • Dogfood in a uv-based repository once merged

@hashicorp-vault-sonar-prod

hashicorp-vault-sonar-prod Bot commented Jun 11, 2026

Copy link
Copy Markdown

BUILD-11568

Comment thread config-uv/uv_config.sh
Comment thread config-uv/uv_config.sh
Comment thread config-uv/action.yml
Comment thread config-uv/action.yml

@ross-bragg-sonarsource ross-bragg-sonarsource left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hedinasr
hedinasr marked this pull request as ready for review June 23, 2026 09:38
@hedinasr
hedinasr requested a review from a team as a code owner June 23, 2026 09:38
Copilot AI review requested due to automatic review settings June 23, 2026 09:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new config-uv composite action to configure uv for Repox/Artifactory (via JFrog CLI), including uv index credential injection and dependency caching, plus associated docs and ShellSpec coverage.

Changes:

  • Introduce config-uv composite action (config-uv/action.yml) and its supporting shell script (config-uv/uv_config.sh) + local mise config.
  • Add ShellSpec tests for config-uv and include it in kcov coverage patterns.
  • Document config-uv usage/inputs/outputs in README.md.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
config-uv/action.yml New composite action wiring (Vault auth, caching, mise setup, uv config script execution).
config-uv/uv_config.sh Shell script to configure jf config + export UV_INDEX_* env vars.
config-uv/mise.local.toml Local mise tool/env config used during action execution.
spec/config-uv_spec.sh ShellSpec coverage for uv_config.sh behaviors.
README.md Adds config-uv documentation section and TOC entry.
.shellspec Includes config-uv in coverage include-patterns.
.github/workflows/test-update-release-channel.yml Adjusts permissions and adds an extra action invocation in the test workflow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread config-uv/uv_config.sh Outdated
Comment thread config-uv/action.yml
Comment thread README.md
Comment thread README.md
Comment thread .github/workflows/test-update-release-channel.yml Outdated
Comment thread config-uv/action.yml
Comment thread .github/workflows/test-update-release-channel.yml Outdated
Comment thread config-uv/action.yml
Comment thread README.md
Comment thread .github/workflows/test-update-release-channel.yml Outdated
@hedinasr
hedinasr force-pushed the feat/hnasr/BUILD-11568-createConfigUv branch from e46040b to a793c12 Compare June 23, 2026 11:40
Comment thread config-uv/uv_config.sh
Comment thread config-uv/action.yml
@hedinasr
hedinasr force-pushed the feat/hnasr/BUILD-11568-createConfigUv branch from 68f61f5 to 0c0757c Compare June 25, 2026 09:34
Add a config-uv composite action that fetches Artifactory reader credentials
from Vault and exposes UV_INDEX_* authentication for the Repox PyPI index.
Configure jf for Repox, cache uv dependencies under .cache/uv, and include
shellspec coverage plus README documentation.
@hedinasr
hedinasr force-pushed the feat/hnasr/BUILD-11568-createConfigUv branch from 0c0757c to 507bd0f Compare June 25, 2026 09:35
@hedinasr
hedinasr enabled auto-merge (rebase) June 25, 2026 09:36
@sonarqubecloud

Copy link
Copy Markdown

@hedinasr
hedinasr merged commit de29c54 into master Jun 25, 2026
16 checks passed
@hedinasr
hedinasr deleted the feat/hnasr/BUILD-11568-createConfigUv branch June 25, 2026 09:38
@gitar-bot

gitar-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown
Code Review 👍 Approved with suggestions 5 resolved / 6 findings

Implements the config-uv composite action for automated credentials and caching. Address the identified token persistence, environment variable sanitization, and error handling for mise to improve security and reliability.

💡 Security: Artifactory token persisted to GITHUB_ENV for whole job

📄 config-uv/uv_config.sh:26-29 📄 config-uv/action.yml:102-111

Unlike config-pip, which writes the token into a local pip.conf file, config-uv writes UV_INDEX_<NAME>_PASSWORD=<access_token> into GITHUB_ENV. This is required so that later uv sync steps can authenticate, but be aware it persists the credential as an environment variable visible to every subsequent step in the job, including any third-party actions invoked afterward. The value is masked in logs only because the vault-action-wrapper registers the secret with ::add-mask::; the persistence itself broadens the exposure surface compared to a file written under $HOME. This is largely inherent to how uv consumes index credentials, so no change may be possible, but it is worth documenting the trade-off and ensuring no untrusted steps run later in the same job.

✅ 5 resolved
Bug: mise backup/restore use mismatched working directories

📄 config-uv/action.yml:68-73 📄 config-uv/action.yml:124-131
The mise backup logic and the restore logic run in different directories, which breaks when inputs.working-directory is not the default ..

  • The "Set local action paths" step (lines 68-73) has no working-directory, so it runs at the workspace root: it moves existing mise files into $mise_backup and cps mise.local.toml into the workspace root.
  • The "Configure uv authentication" step (lines 124-131) sets working-directory: ${{ inputs.working-directory }}, so the restore block (rm mise.local.toml, mv "$MISE_BACKUP"/* ./ ...) executes inside that subdirectory.

When working-directory is a subdirectory:

  1. rm mise.local.toml fails because the file was created at the workspace root, not the subdirectory. GitHub runs shell: bash with -eo pipefail, so this aborts the step and fails the whole action.
  2. Even if it didn't fail, the backed-up mise files would be restored into the wrong directory, leaving the workspace root permanently polluted with mise.local.toml and missing its original mise files.

Perform the backup and restore in the same directory. Either add working-directory: ${{ inputs.working-directory }} to the backup step, or remove working-directory from the configure step and have uv_config.sh/the build handle the path. Make sure the cp target and the rm/mv operate on the same location.

Edge Case: Caching silently disabled for any disable-caching value except 'false'

📄 config-uv/action.yml:21-23 📄 config-uv/action.yml:93
The cache step is gated on inputs.disable-caching == 'false'. Because the comparison is against the exact string 'false', any other value silently disables caching — including unintended values such as 'False', '0', an empty string, or a typo. The default is 'false', so the happy path works, but a user who passes a non-canonical falsey value will lose caching without any warning. Consider inverting the check to inputs.disable-caching != 'true' so that caching is only disabled when explicitly requested, matching the convention used in the sibling config-npm action.

Bug: mise restore not run when uv_config.sh fails or action errors

📄 config-uv/action.yml:124-131
The mise restore block is appended after $ACTION_PATH_CONFIG_UV/uv_config.sh in the same run: step and is not guarded by always(). Because the step uses -eo pipefail, if uv_config.sh exits non-zero the restore lines never execute. This leaves the workspace with mise.local.toml copied in and the repo's original mise files (mise., .mise., .tool-versions) stranded in the temp backup directory. In self-hosted or reused checkouts this corrupts subsequent steps/runs. Consider moving the restore into a separate step with if: always() (and tolerating a missing backup), so cleanup happens even on failure.

Security: Access token passed as CLI arg and stored in persistent jf config

📄 config-uv/uv_config.sh:37-39
jf config add repox ... --access-token "$ARTIFACTORY_ACCESS_TOKEN" passes the Artifactory access token as a command-line argument. Command-line arguments are visible to any process on the runner via ps//proc, and jf config add writes the credential into the persistent JFrog CLI config (~/.jfrog/jfrog-cli.conf), which then survives for the remainder of the job/runner lifetime. This is a separate exposure sink from the GITHUB_ENV write. On ephemeral GitHub-hosted runners the blast radius is limited, but on self-hosted runners the config (and token) can persist across jobs. Consider clearing the config at the end of the action (e.g. jf config remove repox in an always() cleanup step) so the credential does not linger after the action completes.

Edge Case: Degenerate uv-index-name yields malformed env var names

📄 config-uv/uv_config.sh:23-24
index_name_upper is built by uppercasing the index name and replacing non-alphanumerics with _, then stripping only trailing underscores via sed 's/_*$//'. For a normal name like repox or my-index this works (and the trailing-underscore strip correctly removes the _ produced from echo's newline). However, edge inputs are not guarded: an empty or all-symbol uv-index-name produces UV_INDEX__USERNAME/UV_INDEX__PASSWORD, and a name beginning with a digit (e.g. 2repox) produces UV_INDEX_2REPOX_.... uv would then look up a differently-named variable and authentication would silently fall back to anonymous/public PyPI access, causing confusing 401/resolution failures rather than a clear error. Consider validating that the sanitized index name is non-empty (and optionally that it matches uv's own naming rules) and failing fast with a descriptive message if not.

🤖 Prompt for agents
Code Review: Implements the `config-uv` composite action for automated credentials and caching. Address the identified token persistence, environment variable sanitization, and error handling for `mise` to improve security and reliability.

1. 💡 Security: Artifactory token persisted to GITHUB_ENV for whole job
   Files: config-uv/uv_config.sh:26-29, config-uv/action.yml:102-111

   Unlike `config-pip`, which writes the token into a local `pip.conf` file, `config-uv` writes `UV_INDEX_<NAME>_PASSWORD=<access_token>` into `GITHUB_ENV`. This is required so that later `uv sync` steps can authenticate, but be aware it persists the credential as an environment variable visible to every subsequent step in the job, including any third-party actions invoked afterward. The value is masked in logs only because the vault-action-wrapper registers the secret with `::add-mask::`; the persistence itself broadens the exposure surface compared to a file written under `$HOME`. This is largely inherent to how uv consumes index credentials, so no change may be possible, but it is worth documenting the trade-off and ensuring no untrusted steps run later in the same job.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants