Short-form `Simone/local-ci-cd-system/...@main` resolved to
github.com (DEFAULT_ACTIONS_URL=github) -> "authentication required:
Repository not found". Use the full gitea.emulab.it URL like
self-test.yml.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Passo 6: self-test.yml validated — in-guest clone (default) and
host-side clone+zip, Windows + Linux, all SUCCESS. Artifact handling
github-free.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Runner fetches the composite action from @main. Propagates the
default-on transport/submodules inputs and explicit flag forwarding.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The job command previously discarded --use-git-clone and --submodules
(`del`) and always in-guest cloned with submodules off — making both
action inputs dead no-ops (submodule repos silently broken).
- job.py: --use-git-clone/--host-clone and --submodules/--no-submodules
are real booleans defaulting to ON. Default = in-guest clone with
submodules. --host-clone clones on the host into a temp dir
(_host_clone) and transfers a zip; temp dir cleaned in finally.
clone_submodules now honoured (was hardcoded False).
- action.yml: use-git-clone / submodules default 'true'; forward the
explicit positive/negative flag so the Python default is overridden
deterministically.
- self-test.yml: add smoke-{windows,linux}-hostclone jobs covering the
host-side transport (default jobs already cover in-guest).
- tests: default-transport, host-clone, and --no-submodules coverage.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Artifact github.com dependency removed (fix 2 applied). Remaining:
actions/checkout@v4 in lint.yml. Recorded as deferred §8.1 with
revisit conditions (air-gapped host / total github.com independence).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Runner fetches the composite action from @main. Propagates the
github.com-free artifact handling (host-side collect dir).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
actions/upload-artifact and download-artifact run code fetched from
github.com (and v4 is GHES-incompatible, v3 deprecated). The runner
host is single with a shared filesystem, so the orchestrator's
host-side collect dir is the artifact handoff:
- action.yml: replace the two upload-artifact steps with
host-path report steps; artifacts stay under F:\CI\Artifacts and
are aged by Invoke-RetentionPolicy.ps1.
- build-nsInnoUnp.yml: release job reads
F:\CI\Artifacts\{run_id}-{run_attempt}-{target} directly instead of
download-artifact; existing Gitea REST release-asset upload unchanged.
Tradeoff (accepted): artifacts are no longer downloadable from the
Gitea Actions run page for non-tag builds — only on host disk, and as
release assets for tagged builds.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Windows produced an intermediate C:\CI\output\artifacts.zip that
upload-artifact then re-zipped (zip-in-zip), while Linux deposited raw
files. Make both paths consistent: the build stages raw outputs into a
collect dir; collect zips it only as a transport archive, fetches, and
extracts into the host artifact dir; actions/upload-artifact produces
the single final archive.
- _windows_build: param artifact_zip -> output_dir; stage raw files
(in-place when source IS the collect dir, else wipe+copy), no
Compress-Archive; absolute artifact-source resolved.
- _windows_collect: zip guest dir as transport, fetch, extract (mirror
_linux_collect); guest_path is now the collect directory.
- job.py / build_run CLI: pass output_dir; rename --guest-artifact-zip
-> --guest-output-dir.
- Tests updated for the raw-file contract.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
git clone --depth 1 --branch X only fetches the branch tip. When the
branch advances between workflow trigger and runner pickup, checking
out the pinned commit failed with "reference is not a tree: <sha>".
Fetch that exact commit (git fetch --depth 1 origin <sha>) before
checkout, on both Linux (SSH) and Windows (WinRM) paths.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two bugs made the Linux smoke "succeed" with an empty artifact:
- artifact_source was always joined as workdir + '/' + src, so an
absolute source (/opt/ci/output) became /opt/ci/build//opt/ci/output
and was never found — only a non-fatal WARNING was logged.
- `rm -rf output_dir` ran unconditionally; when the build writes
directly into the collect dir (the smoke case: output == source),
it deleted the build output before collection.
Resolve absolute vs workdir-relative; when the source is the output
dir, collect in place without wiping; a missing/empty source is now a
hard failure instead of a silent empty artifact.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Reconcile docs with the end-to-end pipeline fixes:
- upload/download-artifact @v4 -> @v3 (Gitea GHES) in WORKFLOW-AUTHORING
and workflow-example.yml; add Common Mistakes rows (v4, action ref
form + DEFAULT_ACTIONS_URL, public action repo).
- BEST-PRACTICES / README / HOST-SETUP: guest credential must live in
the LocalSystem vault with a host-qualified username; document
Set-CIGuestCredential.ps1 / Test-CIGuestWinRM.ps1 and auth=ntlm.
- README / AGENTS / HOST-SETUP: production venv install is NON-editable
(LocalSystem); no CI workflow may install into it.
- HOST-SETUP: add DEFAULT_ACTIONS_URL=github + full-URL uses: + public
repo + @main requirements discovered during validation.
- Correct stale repo name local-ci-system -> local-ci-cd-system.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Windows manual smoke used --guest-artifact-source
'C:\ci\workspace\artifact.txt' (a stale absolute path that does not
exist in the build flow; workdir is C:\CI\build). The build command
writes artifact.txt into the workdir, so the source must be relative
'artifact.txt' — matching the Linux example.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two Windows-guest build bugs:
- The build command was wrapped in `cmd /c`, so PowerShell-authored
commands failed ("'New-Item' is not recognized"). Run it as PS
(seed LASTEXITCODE=0 so PS-only commands exit cleanly).
- artifact_source was always Join-Path'd with the workdir; an absolute
source (C:\CI\output) became C:\CI\build\C:\CI\output. Use the path
as-is when rooted, else Join-Path the workdir.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Stops a main-triggered Lint run from poisoning the shared production
venv (see feature branch commit for full rationale).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The python lint job set VENV_DIR=F:\CI\python\venv (the shared
orchestrator venv) and ran `pip install -e ".[dev]"`. Every lint run
repointed ci_orchestrator at the lint job's transient checkout; once
act_runner cleaned that dir, all later smoke/build jobs failed with
"No module named ci_orchestrator". Use a job-local venv under
github.workspace, rebuilt fresh each run.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Reproduces the orchestrator WinRM readiness probe as SYSTEM (the
act_runner account) and surfaces the real error the silent
is_ready() swallows: TCP reachability, guest hostname from the TLS
cert CN, and an auth x username-form matrix, with a classified
fix recommendation.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
pypsrp defaults to auth='negotiate', which attempts Kerberos with no
domain and fails under SSPI with SEC_E_UNKNOWN_CREDENTIALS for the
workgroup ci_build account. Default to 'ntlm' (configurable). The
guest username must be host-qualified (WINBUILD-2025\ci_build) and
stored that way in the credential vault.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Runner fetches the composite action from @main. Propagates the fix
that stops an empty artifact-path output from globbing the F: drive.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
PowerShell 5.1 `Out-File -Encoding utf8` prepends a UTF-8 BOM. The
act_runner GITHUB_OUTPUT parser then read the key as "artifact-path",
so steps.invoke-ci.outputs.artifact-path resolved empty. Combined with
the trailing backslash, the upload path became "\" -> the F: drive root,
causing upload-artifact to ingest the entire drive (hundreds of GB of
unrelated files).
- Append outputs with UTF8Encoding($false) (no BOM).
- Throw if artifactPath is empty instead of emitting nothing.
- Drop the trailing backslash; use /*.log for the diagnostic glob.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
act_runner runs as LocalSystem; `pip install -e .` writes a .pth to a
path LocalSystem can't resolve (N: user drive or a transient
F:\CI\RunnerWork job dir), causing "No module named ci_orchestrator".
Prescribe `pip install .` and warn about the cd target.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Runner fetches the composite action from @main; main still had
upload-artifact@v4 which fails on Gitea (GHESNotSupportedError).
Brings the v3 action.yml from feature/python-rewrite-and-linux-migration.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Stores a guest-VM credential into the LocalSystem keyring vault via a
transient SYSTEM scheduled task, using the production venv's keyring
(the backend ci_orchestrator reads). Fixes the per-user vault mismatch
that made act_runner (LocalSystem) fail with "Credential not found in
keyring" for cmdkey/UI-stored credentials.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Gitea act_runner reports as GHES; @actions/artifact v2 (upload/
download-artifact@v4) uses the Twirp API Gitea does not implement,
failing with GHESNotSupportedError. v3 uses the artifact protocol
Gitea supports.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Required so `uses: .../local-ci-build@main` resolves: the action only
existed on feature/python-rewrite-and-linux-migration. Brings just the
action.yml (host-side orchestrator unchanged) without merging the full
migration branch.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Update --cov-fail-under in lint workflow + docs (AGENTS, README, ARCHITECTURE). Note: A5 closeout reported 80.10%% so this run will likely fail until additional tests are added.
Configure system Python path once in runner/config.yaml (runner.envs) instead of probing N candidate locations in the workflow. Workflow now fails fast with a clear error if the env is unset or points to a missing file. Document the new env in AGENTS.md.
Reorder candidates to put C:\Program Files\Python314 first (verified install path on the production host). Drop py.exe -3.11 hint to plain -3 since host has only 3.14.
act_runner SYSTEM context may not have py.exe or python.exe in PATH. Try a list of common install paths (C:\Python3XX, Program Files, LocalAppData) and allow override via CI_PYTHON_LAUNCHER env var.
Native stderr from a broken python.exe shim ('No Python at ...') becomes a terminating exception under \Continue='Stop' BEFORE \0 can be read. Wrap the probe in try/catch + SilentlyContinue.
The venv at F:\CI\python\venv may exist but be broken if its pyvenv.cfg points to a deleted base interpreter (e.g. a stale actions/setup-python tool_cache). Detect this by running 'python --version' and rebuild the venv with py.exe -3.11 if it fails.
act_runner runs as SYSTEM and does not have plain 'python' in PATH; use py.exe launcher (-3.11) to bootstrap the venv when missing. The production venv at F:\CI\python\venv normally already exists, so the bootstrap is just a fallback. Also align coverage threshold to 80% (raised in A5, see AGENTS.md).
Update active docs (PhaseA/B checklists, README) after rename of feature/python-rewrite-phase-a -> feature/python-rewrite-and-linux-migration. Historical A1-A5 closeouts left untouched as they document state at the time of writing.