Skip to content

forgejo-runner (FIX): support generated/unattended mode and configurable runner labels#1645

Merged
MickLesk merged 9 commits intocommunity-scripts:mainfrom
WaffleThief123:forgejo-runner-fix
Apr 30, 2026
Merged

forgejo-runner (FIX): support generated/unattended mode and configurable runner labels#1645
MickLesk merged 9 commits intocommunity-scripts:mainfrom
WaffleThief123:forgejo-runner-fix

Conversation

@WaffleThief123
Copy link
Copy Markdown
Contributor

@WaffleThief123 WaffleThief123 commented Mar 30, 2026

✍️ Description

  • Fix install script calling nonexistent prompt_input_required and show_missing_values_warning functions from build.func, which causes the install to fail
  • Export app-specific variables (var_forgejo_instance, var_forgejo_runner_token, var_runner_labels) in the CT script so they cross the lxc-attach boundary into the container
  • Replace broken calls with standard read -r -p prompts that skip when variables are pre-set, enabling mode="generated" (unattended) installs
  • Make runner labels configurable — additional labels passed via var_runner_labels are appended to the default, not replacing it (NOT LXC CONTAINER LABELS)
  • Update default runner image from node:20-bookworm to node:22-bookworm (Node 22 LTS; Node 20 EOL April 2026)
    NOTE: I have weighed using node:lts as the image tag, however that would make the CI runner not deploy in the same manner every time, undermining a core principle in the DevOps world: Reproducible Builds.

🔗 Related PR / Issue

✅ Prerequisites (X in brackets)

  • Self-review completed – Code follows project standards.
  • Tested thoroughly – Changes work as expected.
  • No breaking changes – Existing functionality remains intact.
  • No security risks – No hardcoded secrets, unnecessary privilege escalations, or permission issues.

🛠️ Type of Change (X in brackets)

  • 🐞 Bug fix – Resolves an issue without breaking functionality.
  • New feature – Adds new, non-breaking functionality.
  • 💥 Breaking change – Alters existing functionality in a way that may require updates.
  • 🆕 New script – A fully functional and tested script or script set.
  • 🌍 Website update – Changes to website-related JSON files or metadata.
  • 🔧 Refactoring / Code Cleanup – Improves readability or maintainability without changing functionality.
  • 📝 Documentation update – Changes to README, AppName.md, CONTRIBUTING.md, or other docs.

🔍 Code & Security Review (X in brackets)

  • Follows Code_Audit.md & CONTRIBUTING.md guidelines
  • Uses correct script structure (AppName.sh, AppName-install.sh, AppName.json)
  • No hardcoded credentials

📋 Additional Information

Test plan

  • Interactive install: verify prompts appear for instance URL, token, and additional labels
  • Interactive install with no extra labels: verify only linux-amd64:docker://node:22-bookworm is registered
  • Interactive install with extra labels: verify default + custom labels are both registered
    - Unattended install with mode="generated" and all var_* set: verify no prompts, container created with correct config Test 4 has been withheld at this time, pending question asked in issue Forgejo-Runner #1576 (comment)
  • Unattended install with missing token: verify hard error and clean exit

Once steps have been tested (and gif of output provided here) I will update and remove DRAFT, indicating ready for merge.


📦 Application Requirements (for new scripts)

brevity removal

🌐 Source

brevity removal

@WaffleThief123 WaffleThief123 requested a review from a team as a code owner March 30, 2026 00:45
@WaffleThief123 WaffleThief123 marked this pull request as draft March 30, 2026 00:53
@WaffleThief123
Copy link
Copy Markdown
Contributor Author

WaffleThief123 commented Mar 30, 2026

I recorded each of my tests using https://github.com/asciinema/asciinema and https://github.com/asciinema/agg to render them as gifs after modifying out internal information (storage and template devices, network info, forgejo url and key) as well as removing long waits (OS/container updates, installs, etc). Each test case is shown below.

Test 1

Test 1: Interactive install: verify prompts appear for instance URL, token, and additional labels

test1-interactive

Test 2

Test 2: Interactive install with no extra labels: verify only linux-amd64:docker://node:22-bookworm is registered

test2-unattended-default

Test 3

Test 3: Interactive install with extra labels: verify default + custom labels are both registered

test3-unattended-labels

Test 4 has been withheld at this time, pending question asked in issue #1576 (comment)

Test 5

Test 5: Unattended install with missing token: verify hard error and clean exit

test5-missing-token

…le runner labels

- Export app-specific variables (var_forgejo_instance, var_forgejo_runner_token,
  var_runner_labels) in ct script so they survive lxc-attach into the container
- Replace nonexistent prompt_input_required/show_missing_values_warning calls
  with standard read prompts that skip when variables are pre-set
- Add hard error when no runner token is provided
- Make runner labels configurable via var_runner_labels instead of hardcoded
- Update default runner image from node:20-bookworm to node:22-bookworm (Node 22 LTS)
CT script hardcoded the upstream URL for build.func, so the install
script was always fetched from upstream — ignoring fork/branch fixes.
Now respects COMMUNITY_SCRIPTS_URL override, consistent with how
build.func already handles this for all other resource fetching.
core.func overwrites $HOSTNAME with a formatted emoji string for display
purposes, causing runner registration to send garbled ANSI codes as the
runner name. Use $(hostname) to get the actual system hostname.
forgejo-runner register writes .runner config to the current working
directory. The install script runs in a temp directory (via build.func),
so the config was lost on cleanup. The systemd service expects it in
/root (WorkingDirectory=/root), so cd there before registering.
Abort before build_container if mode is set (unattended) but no
runner registration token was provided. Avoids a 20+ minute container
build only to fail at the registration step.
…active

Check for missing token/URL only when mode is set AND there's no TTY,
so mode=default with a terminal still allows interactive prompts inside
the container.
mode is only set when the user is automating (e.g. mode=default with
var_* overrides). The default bash -c curl invocation leaves mode empty
and shows the whiptail menu, so this check won't affect interactive use.
@WaffleThief123 WaffleThief123 marked this pull request as ready for review April 7, 2026 17:16
@WaffleThief123 WaffleThief123 changed the title DRAFT: forgejo-runner (FIX): support generated/unattended mode and configurable runner labels fix(forgejo-runner): support generated/unattended mode and configurable runner labels Apr 7, 2026
@WaffleThief123 WaffleThief123 changed the title fix(forgejo-runner): support generated/unattended mode and configurable runner labels forgejo-runner (FIX): support generated/unattended mode and configurable runner labels Apr 7, 2026
@github-actions github-actions Bot added the stale label Apr 14, 2026
@github-actions github-actions Bot closed this Apr 21, 2026
@CrazyWolf13 CrazyWolf13 reopened this Apr 21, 2026
@CrazyWolf13
Copy link
Copy Markdown
Member

@lengschder97 could you take a look and review this?

@WaffleThief123 can you revert the change at the very top with the URL for sourcing the funcs?

@community-scripts community-scripts deleted a comment from github-actions Bot Apr 23, 2026
@community-scripts community-scripts deleted a comment from github-actions Bot Apr 23, 2026
@CrazyWolf13 CrazyWolf13 removed the stale label Apr 23, 2026
@CrazyWolf13 CrazyWolf13 reopened this Apr 23, 2026
Comment on lines +35 to +39
if [[ -n "${var_runner_labels:-}" ]]; then
RUNNER_LABELS="${DEFAULT_RUNNER_LABELS},${var_runner_labels}"
else
RUNNER_LABELS="${DEFAULT_RUNNER_LABELS}"
fi
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can't you do something like this?

var_keyctl="${var_keyctl:-1}"

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.

That pattern works for var_forgejo_instance since it has a sensible default (https://codeberg.org), and that's already how ct/forgejo-runner.sh declares it at the top of the file. But it doesn't work for the other two:

  • var_forgejo_runner_token has no sensible default. Every install needs a unique secret from the user's Forgejo instance. The previous code used REPLACE_WITH_YOUR_TOKEN as a fallback, but that just delays failure: the runner registration call rejects it and the install dies mid-way with a confusing auth error.

  • var_runner_labels is opt-in extra labels appended to a default. Using ${var_runner_labels:-} silently would skip the interactive prompt entirely for users running the script the normal way (bash -c "$(curl …ct/forgejo-runner.sh)").

The read -r -p block is what gives the interactive UX. Happy to swap to a helper if there's a preferred one. prompt_input_required was the original choice, but it returns a fallback string on timeout or non-TTY rather than failing, which is what landed us with the broken REPLACE_WITH_YOUR_TOKEN behavior.


msg_info "Registering Forgejo Runner"
export DOCKER_HOST="unix:///run/podman/podman.sock"
cd /root
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why is this needed now?

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.

forgejo-runner register writes the resulting .runner config file to the current working directory, and the systemd unit we generate a few lines later runs the daemon with WorkingDirectory=/root. Without the cd, the config lands wherever build.func or install.func left CWD (varies by phase, typically not /root), the daemon can't find it on start, and the runner sits idle. cd /root aligns the register step with the service's working dir. We can always change the workdir, but generally if you need to drop into a worker shell, you're likely doing it to modify your .runner config, so keeping it right where the user drops into is my opinionated choice. I am open to a --config /root/.runner flag instead if you prefer that, but I think that adds additional noise.

--token "$FORGEJO_RUNNER_TOKEN" \
--name "$HOSTNAME" \
--labels "linux-amd64:docker://node:20-bookworm" \
--name "$(hostname)" \
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think hostname var is set by our core funcs, why does this need changing?

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.

It is set by core funcs, and that's the problem. misc/core.func:114 does this:

HOSTNAME="${TAB}🏠${TAB}${CL}"

It's clobbering the bash builtin $HOSTNAME (which Bash normally sets to the system hostname) with a decorative emoji used elsewhere as a label icon. So --name "$HOSTNAME" was registering every runner with literal "🏠" wrapped in tab and color escape codes, which is also why duplicate runner names showed up upon re-running the install. $(hostname) calls the system command and bypasses the shadowed variable.

msg_ok "Created Services"

# Show warning if any required values used fallbacks
show_missing_values_warning
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why?

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.

That call only fired the warning if MISSING_REQUIRED_VALUES had entries, which only happened when prompt_input_required returned a fallback string. Now that the install hard-fails up top when the token is missing (and we don't accept fake fallbacks like REPLACE_WITH_YOUR_TOKEN anymore), MISSING_REQUIRED_VALUES is always empty by the time we reach that line, so the call is a no-op. I removed it for clarity, but it's harmless if you'd rather leave it in.

@WaffleThief123
Copy link
Copy Markdown
Contributor Author

WaffleThief123 commented Apr 29, 2026

sorry, been afk, had some life stuff happen, will review and try to get these answered promptly when home from work tonight in ~8hr

Drop the env-var indirection on the build.func source URL; it was a dev
convenience for testing against a fork and adds no user-facing value.
@MickLesk MickLesk merged commit 6d9d446 into community-scripts:main Apr 30, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants