Fix the defects found by the live end-to-end run, add RC-017

- Close stdin for ssh, git, curl and the framework scripts, so a real ssh
  no longer swallows answers meant for later prompts.
- Count LICENSE and LICENSE + README.md (what Gitea creates) as content
  the script made, so a partly created repository can be reused.
- Document the observed token scopes (write:user for user-owned Gitea
  repositories) and the Gitea README.md in the README.
- Correct criterion 2 of MIL-002 (new Proposed version row).
- Record the run and the final security review as RC-017.
- Tests: stdin regression, initial_only reuse, other files count as
  content, example config needs its address edited.

Task: MIL-003#6
Task: MIL-002#1
Refs #20

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 21:41:47 +08:00
co-authored by Claude Sonnet 5.5
parent 0030334e5e
commit 613a288dea
13 changed files with 203 additions and 33 deletions
+1 -1
View File
@@ -47,7 +47,7 @@ run_framework_script() {
abs="$(cd "$dir" && pwd)"
make_temp_file
out="$REPLY"
if ! (cd "$abs" && env PROJECT_ROOT="$abs" bash "framework/scripts/$script" "$@") >"$out" 2>&1; then
if ! (cd "$abs" && env PROJECT_ROOT="$abs" bash "framework/scripts/$script" "$@" </dev/null) >"$out" 2>&1; then
die "the framework script $script failed: $(tail -n 3 "$out" | tr '\n' ' ')"
fi
}
+3 -2
View File
@@ -6,13 +6,14 @@
#
# Provides: git_project, fetch_origin
# git_project DIR ARGS...: run git in DIR. Prompts are switched off, so a
# git_project DIR ARGS...: run git in DIR. Prompts are switched off and stdin
# is closed (git must not eat the answers meant for later prompts), so a
# missing credential or SSH key fails at once instead of waiting for input.
git_project() {
local dir="$1"
shift
GIT_TERMINAL_PROMPT=0 GIT_SSH_COMMAND="${GIT_SSH_COMMAND:-ssh} -o BatchMode=yes" \
git -C "$dir" "$@"
git -C "$dir" "$@" </dev/null
}
# fetch_origin DIR: fetch the Gitea repository into the project. Over SSH the
+1 -1
View File
@@ -71,7 +71,7 @@ http_request() {
# that never contains the request.
HTTP_STATUS="$(curl --silent --max-time "$HTTP_TIMEOUT_SECONDS" \
--connect-timeout 10 --output "$out_file" --write-out '%{http_code}' \
--config "$config_file" "${data_args[@]}" 2>/dev/null)" || curl_status=$?
--config "$config_file" "${data_args[@]}" </dev/null 2>/dev/null)" || curl_status=$?
# The configuration file holds the token and the body may hold another one
# (the mirror password): remove both now instead of at exit.
rm -f -- "$config_file" ${body_file:+"$body_file"}
+10 -6
View File
@@ -28,7 +28,8 @@ check_gitea_license() {
}
# inspect_repository HOST: record in STATE[HOST_repo] whether the repository
# is free (does not exist), empty, license_only or not_empty.
# is free (does not exist), empty, initial_only (just the LICENSE and the
# README.md Gitea adds) or not_empty.
inspect_repository() {
local host="$1" owner name names
owner="$(repo_owner "$host")"
@@ -45,10 +46,13 @@ inspect_repository() {
return 0
fi
expect_status "cannot read the contents of the $(host_label "$host") repository $owner/$name" 200
names="$(json_values "$HTTP_BODY_FILE" name)"
case "$names" in
# Gitea adds a README.md of its own next to the LICENSE when it creates a
# repository with a license (seen on a real server), so both count as the
# content this script creates.
names="$(json_values "$HTTP_BODY_FILE" name | sort | tr '\n' ' ')"
case "${names% }" in
"") STATE[${host}_repo]="empty" ;;
LICENSE) STATE[${host}_repo]="license_only" ;;
"LICENSE" | "LICENSE README.md") STATE[${host}_repo]="initial_only" ;;
*) STATE[${host}_repo]="not_empty" ;;
esac
}
@@ -117,7 +121,7 @@ test_gitea_ssh() {
return 0
fi
output="$(ssh -p "$port" -o BatchMode=yes -o ConnectTimeout=5 \
-o StrictHostKeyChecking=yes -T "git@$host" 2>&1)" || status=$?
-o StrictHostKeyChecking=yes -T "git@$host" </dev/null 2>&1)" || status=$?
if ((status == 0)) || [[ $output == *"successfully authenticated"* ]]; then
STATE[is_ssh_ok]=1
STATE[ssh_note]="passed"
@@ -138,7 +142,7 @@ decide_existing_repositories() {
case "$state" in
free) ;;
empty) STATE[reuse_$host]=1 ;;
license_only)
initial_only)
if [[ $host == gitea ]] && ((PROJECT[has_github])); then
STATE[reuse_$host]=1
else
+1 -1
View File
@@ -45,7 +45,7 @@ report_outcome() {
say "The project is in ${PROJECT[directory]}. Nothing was committed there: review it, then work on a branch."
else
say "To continue: fix the problem named above and run the same command again with --apply."
say "A repository this run created is still empty (or holds only the license), so the next run offers to reuse it."
say "A repository this run created is still empty (or holds only the license and the README Gitea adds), so the next run offers to reuse it."
say "A directory, remotes and submodule created so far are used again by the next run; you are asked before an existing directory or file is touched."
say "Nothing is deleted automatically. To start over, delete the repositories above in the web interface and the project directory by hand."
fi