May 2026 · Part 3 of a 5-part series on migrating CI/CD from GitHub to Codeberg
While Forgejo Actions maintains syntactic parity with GitHub Actions YAML specifications, underlying execution context divergence introduces several compatibility issues. The following boundaries were identified during initial implementation.
github.event_name): The act runner engine fails to reliably propagate the evaluation context for github.event_name triggers (e.g., distinguishing a push payload from a manual workflow_dispatch). Workaround: Suppress dependency on event conditional blocks and parse custom inputs via inputs.deploy_to validation statements instead.workflow_run): Inter-workflow event signaling is unsupported. Multi-stage build-then-deploy architectures dependent on secondary workflow completion must be flattened. Workaround: Consolidate isolated processing definitions into a single orchestration block (ci.yml) using explicit sequential execution requirements (needs).workflow_call): The runtime environment does not interpret the workflow_call keyword. Standard modular architecture patterns are unavailable. Code sharing across independent software repositories must utilize composite action definitions (action.yml) or remain inline within the project root.STAGING_ or PRODUCTION_) directly to keys. This mechanism doubles key quantity and creates operational risk during variables mapping updates.kubectl create secret --from-literal interpolation sequences induces secondary Base64 processing overhead within the act executor layer. This corrupts structural data strings—such as database URLs—causing immediate container runtime failures. Workaround: Enforce data mapping isolation via --from-env-file input targets fed by single-quoted heredoc declarations.The following runtime errors surfaced under production workloads after bypassing primary staging checks.
The act compiler fails to resolve the runs-on property when a job identifier includes hyphen characters (e.g., ci/test-backend). This triggers an ambiguous 'runs-on' key not defined parsing error.
Remediation: Rename all jobs, dependency lists (needs), and concurrency bounds across the codebase to adhere to a snake_case naming convention.
A security patch introduced in Docker 29.5.1 leverages Go’s os.Root implementation to tighten directory boundaries for safety. The act runner mounts internal job workspaces under /var/run/act. Because /var/run exists as a system symlink pointing directly to /run, the stricter engine flags this interaction as a path traversal exception (path escapes from parent), terminating all jobs.
Remediation: Pin the local Docker-in-Docker sidecar instance strictly to version docker:29.5.0-dind to prevent validation failures pending an official patch release.
tea CLI PanicsExecuting pipeline dispatches via the official Codeberg command-line interface (tea) yields an unhandled exception: unexpected end of JSON input. Forgejo processes asynchronous dispatches by returning an empty HTTP status code (204 No Content). The CLI expects a structured JSON object response and throws a fatal parsing error despite successful task scheduling.
Remediation: Suppress standard error monitoring on dispatches; poll task status using structured logging arrays via tea actions runs list.
If a step relies on data mapped from an independent job (e.g., needs.build_backend.outputs.image_sha) but omits that prerequisite from the job’s structural execution graph (needs), Forgejo suppresses the error. The reference evaluates to an empty string. This results in invalid string construction during deployment commands (e.g., backend:-staging), crashing the orchestration process.
Remediation: Enforce explicit configuration tracking on every data-dependent node within the deployment manifest.
Simultaneous execution triggers targeting the same deployment namespace induce race conditions inside the Helm state machine, returning a fatal UPGRADE FAILED: another operation is in progress message. This locks the configuration context into a persistent pending-upgrade error status.
Remediation: Insert an automated recovery routine prior to chart deployment to explicitly check for, and roll back, any locked application releases.
A build pipeline compiles artifacts against a distinct point-in-time reference (abc123). If a parallel merge occurs before the deployment stage executes, a standard repository checkout pulls the new head commit (def456). The deployment container then searches for matching artifacts under the wrong reference, triggering an ImagePullBackOff loop.
Remediation: Bind the lifecycle of all down-stream deployment tasks to the initial build environment’s immutable commit identifier, forcing the checkout stage to target that specific hash.
envsubst)The envsubst utility ignores missing environment parameters, injecting empty strings into configuration templates without outputting warning signals. This creates structural drift, such as compiling application manifests with unassigned connection endpoints.
Remediation: Transition variable extraction from custom shell scripts to native Kubernetes specifications via container-level secretRef arrays.
uv Execution Missing)Using uv run alembic upgrade head within a Kubernetes database migration job crashes if the application’s production layer relies on an optimized, multi-stage Docker build pattern. Multi-stage compilation drops developer toolchains like uv from the final artifact layer to save disk space.
Remediation: Reference the production binary directly via its absolute virtual environment file path: /app/.venv/bin/alembic upgrade head.
.gitignore ConfigurationsA global filter pattern targeting asset files (e.g., *.png) prevents application graphics from inclusion in the Git history tracker. Local builds succeed due to untracked local cache availability, but remote Docker builds (which use the clean Git isolation pool) compile projects with missing assets.
Remediation: Introduce a staging integration check that polls asset endpoints via HTTP headers, checking explicitly for content-type: image/png.
Executing an Alembic auto-generation command (alembic revision --autogenerate) against an outdated local data storage instance creates duplicate table definition blocks (op.create_table). Running this migration file against a synchronized remote database crashes the pipeline due to a DuplicateTable database constraint error.
Remediation: Standardize developer workflows to enforce execution of alembic upgrade head before any schema changes are generated.
Altering auto-generated database migration scripts via comment blocks often leaves stale, unused package imports behind. Subsequent linting phases (Ruff) catch these violations and block the pipeline from advancing.
Remediation: Append database migration directories to the exclusion configuration array within the project’s main linting properties file.
The runner setup downloads environment dependencies (catthehacker/ubuntu:act-22.04) from public Docker Hub infrastructure at the start of every pipeline cycle. External service degradation, network latency, or IP rate-limiting blocks pipeline progress across all tasks.
Remediation: Implement a private mirror of the runner image within a registry hosted on internal network infrastructure.
privileged: true). To isolate this risk, runners are quarantined on a dedicated GKE spot instance node pool with rigid node taints. This isolates potential host compromises to ephemeral, short-lived nodes.