Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
aa50176
feat(action): composite setup action; repo-eval uses it (part of #318)
napetrov Oct 31, 2026
6cd5a9a
fix(action): keep the setup action checkout until the job ends (part …
napetrov Oct 31, 2026
6ea3442
ci(repo-eval): keep the setup-action comment to two lines
napetrov Oct 31, 2026
c2c8555
ci: move the setup action to actions/setup
napetrov Oct 31, 2026
6c4a171
Address review: key the pip cache file under the workspace
napetrov Oct 31, 2026
71dbbbf
fix(setup): check the action out at dokimi-ref from its own repository
napetrov Nov 1, 2026
5b88af0
fix(setup): drop a comment about a post step, widen zizmor's hook, ti…
napetrov Nov 1, 2026
3aa37ff
fix(setup): drop the pip cache; out-dir newline; pin the action commit
napetrov Nov 1, 2026
16df6e9
fix(setup): keep the out-dir path intact when capturing it
napetrov Nov 1, 2026
ff84af5
Treat an out-dir starting with a dash as a path
antonwolfy Nov 1, 2026
3181a51
Run the newline cwd test with out-dir set to a dot
antonwolfy Nov 1, 2026
a2f5d46
Assert the exact action-sha mapping and recorder command
antonwolfy Nov 1, 2026
0880899
Prefix a relative out-dir with ./ so a lone dash is a path
antonwolfy Nov 1, 2026
fe4f247
ci(repo-eval): check the setup action out at a commit resolved first
napetrov Nov 1, 2026
feae4f2
Merge remote-tracking branch 'intel/main' into pr319-land1031
napetrov Nov 1, 2026
ced2d66
ci(repo-eval): install the action's resolved commit when both repos m…
napetrov Nov 1, 2026
1817460
test(ci): two-line comment for the repo-eval wiring test
napetrov Nov 1, 2026
c1f06d9
Accept an uppercase 40-digit SHA as dokimi-ref and lower-case it
antonwolfy Nov 1, 2026
6931263
test(ci): pin the setup wiring: package commit, no credentials, insta…
napetrov Nov 1, 2026
1de901d
test(ci): the wiring tests check needs: validate and the install URL …
napetrov Nov 1, 2026
caf19ac
Merge remote-tracking branch 'intel/main' into pr319-land1031
napetrov Nov 1, 2026
ac84b38
Allow a slash in a tag name in both dokimi-ref resolvers
antonwolfy Nov 1, 2026
ef19fa0
Allow a plus in a tag name in both dokimi-ref resolvers
antonwolfy Nov 1, 2026
5db7477
Merge remote-tracking branch 'intel/main' into pr319-land1031
napetrov Nov 2, 2026
e94a00a
test(setup): pin the full lock URL and the validate output dokimi-sha…
napetrov Nov 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ jobs:
- name: zizmor
if: ${{ !cancelled() }}
working-directory: .
run: zizmor --offline --min-severity medium .github/workflows
run: zizmor --offline --min-severity medium .github/workflows actions
# Every tracked file carries the SPDX license header; scope and exceptions
# are in .github/.licenserc.yaml. A `uses:` step, so `make ci-local` skips
# it (the config's header comment has the docker command for a local run).
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/repo-eval-self.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ on:
- 'dokimi/pyproject.toml'
- '.github/workflows/repo-eval.yml'
- '.github/workflows/repo-eval-self.yml'
- 'actions/**'
workflow_dispatch:
inputs:
tasks:
Expand All @@ -45,13 +46,14 @@ jobs:
# The commit under test: the merge commit on a pull request.
dokimi-ref: ${{ github.sha }}
dokimi-repository: ${{ github.repository }}
dokimi-action-repository: ${{ github.repository }}
manifest: .agent-eval/repo-eval.yaml
tasks: ${{ inputs.tasks || 'changed' }}
smoke-tasks: fix-degrade-pre review-pr-conventions
# Every `paths:` entry above outside .agent-eval/, as a prefix.
smoke-paths: >-
dokimi/dokimi/repos/ dokimi/dokimi/commands/repo dokimi/dokimi/schemas/repo_
dokimi/requirements.lock.txt dokimi/pyproject.toml .github/workflows/repo-eval.yml
dokimi/requirements.lock.txt dokimi/pyproject.toml .github/workflows/repo-eval.yml actions/
max-parallel: 4
# intel-ubuntu-latest: see ci.yml.
runs-on: ${{ github.repository_owner == 'intel' && 'intel-ubuntu-latest' || 'ubuntu-latest' }}
Expand Down
123 changes: 77 additions & 46 deletions .github/workflows/repo-eval.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,14 @@ on:
required: true
type: string
dokimi-repository:
description: Repository dokimi-ref is in (owner/name), for testing a fork
description: Repository the dokimi package is installed from (owner/name), for testing a fork
required: false
type: string
default: intel/dokimi
dokimi-action-repository:
description: >-
Repository the setup action is checked out from (owner/name). It holds the commit
`dokimi-ref` names, so a fork's `dokimi-ref` needs this set to the fork too.
required: false
type: string
default: intel/dokimi
Expand Down Expand Up @@ -107,7 +114,8 @@ jobs:
permissions:
contents: read
outputs:
dokimi-sha: ${{ steps.ref.outputs.sha }}
dokimi-sha: ${{ steps.dokimi.outputs.sha }}
action-sha: ${{ steps.action.outputs.sha }}
id: ${{ steps.select.outputs.id }}
tasks: ${{ steps.select.outputs.tasks }}
steps:
Expand All @@ -117,42 +125,57 @@ jobs:
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
with:
python-version: '3.13'
# A SHA is taken as it is; a tag is resolved to the commit it names, so the
# later jobs install the same commit even if the tag moves meanwhile.
- name: Resolve dokimi-ref
id: ref
# The setup action's commit, resolved before any checkout: actions/checkout takes a branch that shares a
# tag's name, so the ref goes in as a commit. A branch is refused here, before the action's code runs.
- name: Resolve the setup action commit
id: action-ref
shell: bash
env:
REF: ${{ inputs.dokimi-ref }}
DOKIMI_REPO: ${{ inputs.dokimi-repository }}
ACTION_REPO: ${{ inputs.dokimi-action-repository }}
run: |
if ! [[ "$DOKIMI_REPO" =~ ^[A-Za-z0-9-]+/[A-Za-z0-9._-]+$ ]]; then
echo "::error title=dokimi-repository::dokimi-repository is not owner/name"
if ! [[ "$ACTION_REPO" =~ ^[A-Za-z0-9-]+/[A-Za-z0-9._-]+$ ]]; then
echo "::error title=dokimi-action-repository::dokimi-action-repository is not owner/name"
exit 1
fi
if [[ "$REF" =~ ^[0-9a-f]{40}$ ]]; then
sha=$REF
elif [[ "$REF" =~ ^[A-Za-z0-9][A-Za-z0-9._-]*$ ]]; then
# An annotated tag's commit is its peeled (^{}) line.
sha=$(git ls-remote --tags "https://github.com/$DOKIMI_REPO" \
sha=
if [[ "$REF" =~ ^[0-9A-Fa-f]{40}$ ]]; then
sha=${REF,,}
elif [[ "$REF" =~ ^[A-Za-z0-9][A-Za-z0-9._/+-]*$ ]]; then
sha=$(git ls-remote --tags "https://github.com/$ACTION_REPO" \
| awk -v t="refs/tags/$REF" '$2 == t "^{}" { p = $1 } $2 == t { l = $1 } END { print (p != "" ? p : l) }')
fi
if ! [[ "${sha:-}" =~ ^[0-9a-f]{40}$ ]]; then
echo "::error title=dokimi-ref::dokimi-ref is neither a 40-digit commit SHA nor a tag of $DOKIMI_REPO"
if ! [[ "$sha" =~ ^[0-9a-f]{40}$ ]]; then
echo "::error title=dokimi-ref::dokimi-ref is neither a 40-digit commit SHA nor a tag of $ACTION_REPO"
exit 1
fi
echo "sha=$sha" >> "$GITHUB_OUTPUT"
echo "dokimi $DOKIMI_REPO@$REF -> $sha"
- name: Install dokimi
env:
SHA: ${{ steps.ref.outputs.sha }}
DOKIMI_REPO: ${{ inputs.dokimi-repository }}
run: |
# The lock is hashed, and pip cannot hash a git URL: install the lock, then dokimi without deps.
pip install --require-hashes -r "https://raw.githubusercontent.com/$DOKIMI_REPO/$SHA/dokimi/requirements.lock.txt"
pip install --no-deps "dokimi @ git+https://github.com/$DOKIMI_REPO@$SHA#subdirectory=dokimi"

# The setup action, at the commit resolved above (sparse to actions/).
- name: Check out the setup action
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ inputs.dokimi-action-repository }}
ref: ${{ steps.action-ref.outputs.sha }}
path: .dokimi-action
Comment on lines +158 to +160

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · medium
Must-fix: With a supported tag such as dokimi-ref: vX.Y.Z, validate can check out action commit A, then scan and tasks-check can check out commit B if the tag moves while validate runs or matrix jobs queue. Those jobs still install validate's pinned package SHA, so they can execute a different setup implementation against the old package (or fail if the action path/inputs changed). This affects both downstream checkout blocks. Capture the actual action checkout's commit in validate (e.g. git -C .dokimi-action rev-parse HEAD), expose it as a separate job output, and use that SHA for downstream action checkouts; do not assume the package SHA identifies the action commit when the repositories differ. Update the checkout tests to enforce this pinning.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 3aa37ff. validate records the commit its setup-action checkout resolved to (git -C .dokimi-action rev-parse HEAD) as the job output action-sha.
scan and tasks-check check the action out at needs.validate.outputs.action-sha, not at dokimi-ref, so a tag that moves mid-run cannot split the jobs. The package was already pinned by dokimi-sha.
Test: test_downstream_jobs_check_the_action_out_at_the_commit_validate_recorded in dokimi/tests/test_repo_eval_action_checkout.py.

sparse-checkout: /actions/
sparse-checkout-cone-mode: false
persist-credentials: false
Comment thread
antonwolfy marked this conversation as resolved.
Resolved
# The commit the setup action was checked out at. The downstream jobs check the action out at
# this SHA: a tag in dokimi-ref may move after this job, and the package SHA does not name the action.
- name: Record the setup action commit
id: action
shell: bash
run: echo "sha=$(git -C .dokimi-action rev-parse HEAD)" >> "$GITHUB_OUTPUT"
# Installs dokimi. With one repository for both, the commit resolved above is passed on: a second
# ls-remote of a tag that has moved would install another commit than the action it runs.
- name: Set up dokimi
id: dokimi
uses: ./.dokimi-action/actions/setup
Comment on lines +172 to +174

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

bug · high
Must-fix: This newly introduced setup call always fails with the current composite action, including when out-dir is omitted. In actions/setup/action.yml, dir=$(cd "$out" && pwd && printf x); dir=${dir%x} preserves the newline that pwd itself prints. Removing x leaves that newline in dir, so the subsequent newline check exits 1 for every normal directory. Consequently validate never runs, and scan/tasks-check are skipped (their setup calls have the same defect). Capture the directory without adding a newline, e.g. dir=$(cd "$out" && printf '%s' "$PWD" && printf x); dir=${dir%x}, and add a shell-level test that default setup succeeds while newline-containing paths are rejected.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Same root cause, fixed in 16df6e9 (the out-dir capture in actions/setup/action.yml). A normal out-dir now passes setup, so validate, scan and tasks-check can run again.

with:
dokimi-ref: ${{ inputs.dokimi-repository == inputs.dokimi-action-repository && steps.action-ref.outputs.sha || inputs.dokimi-ref }}
dokimi-repository: ${{ inputs.dokimi-repository }}
python-version: '3.13'
- name: repo validate
env:
MANIFEST: ${{ inputs.manifest }}
Expand Down Expand Up @@ -294,17 +317,21 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
- name: Check out the setup action
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ inputs.dokimi-action-repository }}
ref: ${{ needs.validate.outputs.action-sha }}
path: .dokimi-action
sparse-checkout: /actions/
sparse-checkout-cone-mode: false
persist-credentials: false
- name: Set up dokimi
uses: ./.dokimi-action/actions/setup
with:
dokimi-ref: ${{ needs.validate.outputs.dokimi-sha }}
Comment thread
antonwolfy marked this conversation as resolved.
Resolved
dokimi-repository: ${{ inputs.dokimi-repository }}
python-version: '3.13'
- name: Install dokimi
env:
SHA: ${{ needs.validate.outputs.dokimi-sha }}
DOKIMI_REPO: ${{ inputs.dokimi-repository }}
run: |
# The lock is hashed, and pip cannot hash a git URL: install the lock, then dokimi without deps.
pip install --require-hashes -r "https://raw.githubusercontent.com/$DOKIMI_REPO/$SHA/dokimi/requirements.lock.txt"
pip install --no-deps "dokimi @ git+https://github.com/$DOKIMI_REPO@$SHA#subdirectory=dokimi"
# Report only: a failing claim does not fail the job (an unreadable
# manifest still does). The table lists the failing claims.
- name: repo scan
Expand Down Expand Up @@ -362,17 +389,21 @@ jobs:
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
- name: Check out the setup action
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: ${{ inputs.dokimi-action-repository }}
ref: ${{ needs.validate.outputs.action-sha }}
path: .dokimi-action
sparse-checkout: /actions/
sparse-checkout-cone-mode: false
persist-credentials: false
- name: Set up dokimi
uses: ./.dokimi-action/actions/setup
with:
dokimi-ref: ${{ needs.validate.outputs.dokimi-sha }}
dokimi-repository: ${{ inputs.dokimi-repository }}
python-version: '3.13'
- name: Install dokimi
env:
SHA: ${{ needs.validate.outputs.dokimi-sha }}
DOKIMI_REPO: ${{ inputs.dokimi-repository }}
run: |
# The lock is hashed, and pip cannot hash a git URL: install the lock, then dokimi without deps.
pip install --require-hashes -r "https://raw.githubusercontent.com/$DOKIMI_REPO/$SHA/dokimi/requirements.lock.txt"
pip install --no-deps "dokimi @ git+https://github.com/$DOKIMI_REPO@$SHA#subdirectory=dokimi"
# Builds the image from the manifest's Dockerfile (the tree without its
# tasks), then grades the null and the oracle workspace in it.
- name: repo tasks check
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ repos:
- repo: https://github.com/zizmorcore/zizmor-pre-commit
rev: c92afdf2c6ca336aaa8f39e2bd8d48f62dbd8e1f # frozen: v1.31.1
hooks:
# The static job's zizmor step: the same command and scope.
# The static job's zizmor step: the same command and scope (workflows and the composite actions).
- id: zizmor
args: [--no-progress, --offline, --min-severity, medium]
files: ^\.github/workflows/[^/]+\.ya?ml$
files: ^(\.github/workflows/[^/]+|actions/(.+/)?action)\.ya?ml$

- repo: https://github.com/gitleaks/gitleaks
rev: 83d9cd684c87d95d656c1458ef04895a7f1cbd8e # frozen: v8.30.1
Expand Down
103 changes: 103 additions & 0 deletions actions/setup/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Copyright (C) 2026 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

name: dokimi setup
description: >-
Installs dokimi at one pinned commit (a SHA, or a release tag resolved to its
commit; a branch is refused) with its locked dependencies, sets up Python, and
exports CI=true. Needs no secret. Callers grant `contents: read` at most.

inputs:
dokimi-ref:
description: >-
dokimi commit SHA (40 hex digits) or release tag to install. Use the ref of the
`uses:` line that pins this action; a branch is refused.
required: true
dokimi-repository:
description: Repository dokimi-ref is in (owner/name), for installing a fork's package
required: false
default: intel/dokimi
python-version:
description: Python the install and the checks run under
required: false
default: '3.13'
out-dir:
description: >-
Directory for the run output, created by this action; empty means
`$RUNNER_TEMP/dokimi-out`. The caller writes its output under it, and uploads the
whole directory as an artifact.
required: false
default: ''

outputs:
sha:
description: The commit installed (40 hex digits)
value: ${{ steps.ref.outputs.sha }}
out-dir:
description: Absolute path of the output directory, to upload
value: ${{ steps.out.outputs.dir }}

runs:
using: composite
steps:
# Resolves the ref before anything is installed: a tag becomes the commit it names
# (the peeled line of ls-remote), so the jobs of one run install the same commit.
- name: Resolve dokimi-ref
id: ref
shell: bash
env:
REF: ${{ inputs.dokimi-ref }}
DOKIMI_REPO: ${{ inputs.dokimi-repository }}
run: |
if ! [[ "$DOKIMI_REPO" =~ ^[A-Za-z0-9-]+/[A-Za-z0-9._-]+$ ]]; then
echo "::error title=dokimi-repository::dokimi-repository is not owner/name"
exit 1
fi
if [[ "$REF" =~ ^[0-9A-Fa-f]{40}$ ]]; then
sha=${REF,,}
elif [[ "$REF" =~ ^[A-Za-z0-9][A-Za-z0-9._/+-]*$ ]]; then
# An annotated tag's commit is its peeled (^{}) line.
sha=$(git ls-remote --tags "https://github.com/$DOKIMI_REPO" \
| awk -v t="refs/tags/$REF" '$2 == t "^{}" { p = $1 } $2 == t { l = $1 } END { print (p != "" ? p : l) }')
fi
if ! [[ "${sha:-}" =~ ^[0-9a-f]{40}$ ]]; then
echo "::error title=dokimi-ref::dokimi-ref is neither a 40-digit commit SHA nor a tag of $DOKIMI_REPO"
exit 1
fi
echo "sha=$sha" >> "$GITHUB_OUTPUT"
echo "dokimi $DOKIMI_REPO@$REF -> $sha"

# No pip cache: a cache restored in a run that checks out the caller's dokimi-ref
# is the poisoning path CodeQL flags (actions/cache-poisoning/poisonable-step).
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ inputs.python-version }}

- name: Install dokimi
shell: bash
env:
SHA: ${{ steps.ref.outputs.sha }}
DOKIMI_REPO: ${{ inputs.dokimi-repository }}
run: |
# The lock is hashed, and pip cannot hash a git URL: install the lock, then dokimi without deps.
pip install --require-hashes -r "https://raw.githubusercontent.com/$DOKIMI_REPO/$SHA/dokimi/requirements.lock.txt"
pip install --no-deps "dokimi @ git+https://github.com/$DOKIMI_REPO@$SHA#subdirectory=dokimi"
Comment thread
antonwolfy marked this conversation as resolved.
Resolved

- name: Output directory and environment
id: out
shell: bash
env:
OUT: ${{ inputs.out-dir }}
run: | # zizmor: ignore[github-env] -- intended: the only value written to GITHUB_ENV is the constant CI=true
out=${OUT:-$RUNNER_TEMP/dokimi-out}
# Refused before mkdir, so a newline name is never created.
if [[ "$out" == *$'\n'* ]]; then echo "::error title=out-dir::out-dir has a newline"; exit 1; fi
# A relative path gets ./ so that a lone - is the directory, not cd's OLDPWD shorthand.
[[ "$out" == /* ]] || out=./$out
mkdir -p -- "$out"
# The x keeps a newline at the end of $PWD from being stripped by the command substitution.
dir=$(cd -- "$out" && printf '%sx' "$PWD"); dir=${dir%x}
Comment thread
antonwolfy marked this conversation as resolved.
Resolved
if [[ "$dir" == *$'\n'* ]]; then echo "::error title=out-dir::out-dir has a newline"; exit 1; fi
echo "dir=$dir" >> "$GITHUB_OUTPUT"
echo "CI=true" >> "$GITHUB_ENV"
4 changes: 3 additions & 1 deletion dokimi/docs/repo-evaluation-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -1703,7 +1703,9 @@ that runs the no-LLM checks on the caller's checkout and needs no secret.
workflow, so it runs the smoke set.
- Other inputs: `manifest`, `max-parallel` (4), `warm` (`--warm`, for a cache that
starts empty on every runner), `runs-on` (`ubuntu-latest`), `timeout-minutes`
(180, per task) and `dokimi-repository` (`intel/dokimi`).
(180, per task), `dokimi-repository` (`intel/dokimi`, the package installed) and
`dokimi-action-repository` (`intel/dokimi`, where the setup action is checked out, at
`dokimi-ref`). Testing a fork's commit sets both to the fork.

```yaml
# .github/workflows/agent-evals.yml in the repository
Expand Down
Loading
Loading