Skip to content

Unattended runs, noconfirm policy and kernel config review (3.5.0-F20, F21, F22, DOC16) - #9

Merged
KeithRaghubar merged 6 commits into
mainfrom
feat/noconfirm-policy
Oct 25, 2026
Merged

KeithRaghubar merged 6 commits into
mainfrom
feat/noconfirm-policy

Conversation

@KeithRaghubar

@KeithRaghubar KeithRaghubar commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Summary

Separates whether sysforge may ask from what a build does, in three steps, plus a docs fix.

  • 3.5.0-DOC16: the commented [group.cosmic] example in packages.toml lists all 28 members of the repo cosmic group (as -git AUR packages, each checked against the AUR).
  • 3.5.0-F20: whether makepkg may prompt is decided by the run, not the profile. makepkg_invoke._base_flags adds --noconfirm to every batch build and leaves it off an interactive one. It deduplicates a copy an older profile still lists. Shipped profiles and fixtures no longer carry the flag. makepkg_flags is outside the flag-drift fingerprint, so this triggers no rebuilds.
  • 3.5.0-F21: --unattended / SYSFORGE_UNATTENDED / [ui] unattended: never prompt, even at a terminal.
    • Every question takes its no-terminal answer: the prompt helpers take their EOF path without reading.
    • Not a global --yes: removals still refuse without one, and the review gate refuses rather than accepts.
    • Never asks for the sudo password: ensure_credentials() skips the prompting sudo -v, and privileged_argv() adds -n.
    • prompt.py is now the only stdin TTY check. tests/test_unattended.py fails on any new one; it found three the first audit missed.
    • Refuse/skip messages say (unattended run) or (no terminal).
  • 3.5.0-F22 (Breaking): the kernel stage's two questions get one answer each.
    • Run the config UI? kernel/config.py::resolve_config_review. It reads kernel.toml review_config (was interactive) and run kernel --no-review-config (was --non-interactive, briefly --no-interactive this cycle).
    • May sysforge ask? prompt.is_interactive() only.
    • The old key is still read with a warning. config check/clean migrate it through RETIRED_KEYS (new still_read field), so nobody gets nconfig back unexpectedly.
    • --no-review-config now only skips the menu: the stage's safety questions are still asked at a terminal.

Notes for review

  • 5dc18c8c went in with one failing test (a conftest boot-entry fake that didn't expect sudo -n); 907d5150 fixes it. Every later commit was verified with make test's own exit status.
  • The F15 migration row in unreleased.md now points released --non-interactive users straight to --no-review-config. --no-interactive never shipped.

Test plan

  • make test: full suite green on the final tree
  • make lint, check-design, check-shipped, check-standards, check-surface, check-roadmap-table
  • Real pty: self-uninstall prompts when attended. It refuses straight away under --unattended and SYSFORGE_UNATTENDED=1.
  • Live-config migration: legacy top-level interactive = false → loader honours it → config check flags it → config clean renames it to review_config = false
  • make e2e (not run on this branch)

🤖 Generated with Claude Code

KeithRaghubar and others added 6 commits October 24, 2026 14:19
…le (3.5.0-DOC16)

The commented [group.cosmic] example in the shipped packages.toml named
three packages; it now names the -git build of all 28 members of the
repo cosmic group, each confirmed present in the AUR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (3.5.0-F20)

Whether makepkg may prompt is a property of the run, not of a build
profile. makepkg_invoke._base_flags now adds --noconfirm to every batch
build and leaves it off an interactive one (build --interactive, an
interactive kernel config), deduplicating a copy an older profile still
lists. The shipped profiles and test fixtures drop the flag; the
--interactive help, man page and zsh completion describe the behaviour
without referring to profile flags.

makepkg_flags is outside the flag-drift fingerprint, so the profile
edit triggers no rebuilds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A global --unattended flag, SYSFORGE_UNATTENDED and [ui] unattended
make every question take the answer it gets with no terminal. The
resolution (flag > env > config > off; the env var also turns a
configured on off for one run) happens once in cli._resolve_unattended
and is applied through prompt.set_unattended.

While set, prompt.is_interactive() is false and prompt_text,
prompt_choice and prompt_key take their EOF path without reading, so a
call site that never checked is_interactive() still cannot block. It is
not a global --yes: removals still refuse, and the review gate still
refuses an unreviewed change. The run-level --interactive flags of
build and update are unchanged.

Five direct stdin TTY checks (makepkg_wrapper, toolchain and kernel
stages, update's plan confirmation, setup, the PKGBUILD review gate)
now go through is_interactive(), and tests/test_unattended.py fails on
any new one outside prompt.py. prompt.no_prompt_reason() puts
"(unattended run)" or "(no terminal)" in every refuse/skip message, and
the kernel stage narrates a chosen skip of the kconfig review instead
of warning about a missing TTY.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sudo reads the terminal itself, so --unattended at a terminal still
stopped at its password prompt. privilege.ensure_credentials() now
returns False without running the prompting sudo -v when the run is
unattended (cached credentials and NOPASSWD still pass the sudo -n true
probe), and privileged_argv() adds -n to every escalation so one that
skipped authenticate() fails fast too.

The stale-sentinel recovery refusal takes its reason from
no_prompt_reason() like the other refuse/skip messages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fake computed its sudo prefix when the fixture ran (attended), so
an escalation made after a test set the run unattended carried an extra
-n and was refused as outside the fake ESP. Fixes the one failure the
previous commit left in test_stage_kernel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (3.5.0-F22)

The kernel stage derived "interactive" in four places with four
formulas. It asked two separate questions:

- run the PKGBUILD's config UI? kernel/config.py::resolve_config_review
  (kernel.toml review_config and not --no-review-config and
  prompt.is_interactive()). Its one answer feeds the kconfig rewrite,
  kconfig_targets validation, the makepkg terminal attachment, the
  AlreadyBuilt arbitration and the install's noconfirm.
- may sysforge ask? prompt.is_interactive() only, for the repo-collision
  and diverged-source confirmations.

BREAKING CHANGE: kernel.toml interactive is now review_config, and
run kernel --non-interactive (--no-interactive earlier this cycle) is
now --no-review-config. The old key is still read with a warning so
nobody gets nconfig back unexpectedly; config check/clean migrate it
(RetiredKey gains still_read so the check does not claim it is
ignored). --no-review-config only skips the menu: the safety questions
are still asked at a terminal; --unattended stops both.

Also drops resolve_already_built's non_interactive parameter and the
dead non_interactive/noconfirm read in update.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@KeithRaghubar
KeithRaghubar merged commit d2231d8 into main Oct 25, 2026
2 checks passed
@KeithRaghubar
KeithRaghubar deleted the feat/noconfirm-policy branch October 25, 2026 01:18
KeithRaghubar added a commit that referenced this pull request Oct 25, 2026
)

## Summary

Two follow-ups to #9: retrying what an unattended run leaves behind, and
a faster `update --devel`.

- **`3.5.0-F23` — `sysforge build --failed`.** Rebuilds only what the
last runs could not finish: packages whose build failed, and packages
refused at the review gate.
- Review refusals used to live only in that run's summary.
`build_core._record_review_refusal` now saves them in build_state.toml's
`[failures]` table with `kind = "review"`, for a target's own change and
for a refused dependency. Each entry clears on the next successful build
or on removal, like build failures already did.
  - `state failed` marks review entries and points at `build --failed`.
- The doctor `state` axis reports them as refusals, not build failures.
- The update summary suggests `build --failed` under `Failed:` and
`Refused at review:`.
- With nothing recorded, `build --failed` exits 0. `sysforge build` with
neither packages nor `--failed` exits 2.
- **`3.5.0-B144` — `update --devel` no longer re-fetches every unchanged
`-git` AUR repo.** `--devel` asks whether *upstream* moved, and the
version check answers that itself (`ls-remote` / `pkgver()`). So VCS
packages now go through the RPC short-circuit like any other package,
and the scheduler's `force_devel` is gone. Fixed along the way:
- **Name collision.** The short-circuit matched the RPC entry by name
only. It now requires the checkout's `origin` to be that pkgbase's own
AUR repo (`_rpc_vouches`, read strictly by the new
`aur.aur_origin_pkgbase`). A fork, another package's repo or a missing
origin always fetches.
- **Fork metadata.** RPC fields are cached only when the entry vouches
for the checkout (`_record_rpc`). Otherwise the new
`SourceMetaCache.forget_rpc` clears them, so a checkout moved from a
fork back to the AUR fetches once first.
- **Source freeze.** Under the freeze, a VCS package that would
short-circuit returns `STATUS_FROZEN`, since its version check needs
upstream. This keeps `update --devel --frozen` exiting 1 instead of
reporting `DEVEL_EVAL_FAILED` and exiting 0.
- **Test.** A `-git` package still rebuilds when only upstream moved.
The existing `--devel` rebuild tests ran offline and never went through
source sync.

## Review

The B144 change was reviewed by the `pkgbuild-reviewer` agent before
commit. Its findings are all addressed in `776fd354`:
- **F1 (medium).** Under `--devel --frozen`, a skipped VCS package ended
up as `DEVEL_EVAL_FAILED` and the run exited 0.
- **C1–C3.** The fork-metadata, fail-open origin and host-only match
gaps described above.
- **C4.** Stale `update.md` text.

## Test plan

- [x] `make test`: full suite green (7681 at the fix commit;
`test_update.py` green with the added regression test)
- [x] `make lint`, `check-design`, `check-shipped`, `check-standards`,
`check-surface`, `check-roadmap-table` (re-run after rebasing onto the
squashed #9)
- [x] Real `git init` checkouts in the origin tests:
  - HTTPS and `aur@aur.archlinux.org:` origins skip the fetch;
  - a fork, another package's repo and no origin all fetch;
  - switching a checkout from a fork back to the AUR fetches once;
- the freeze returns `STATUS_FROZEN`, and `--thaw` lets the package
through.
- [x] A real `sysforge update --devel` on the dev machine: source sync
should drop to seconds when nothing changed on the AUR
- [x] `make e2e` (CI `e2e` job)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

1 participant