GitLab CI¶
The GitLab equivalent of the GitHub Actions guide. The job definition
is inlined below; copy it into your .gitlab-ci.yml.
CI/CD variables¶
In Project → Settings → CI/CD → Variables, define (mark them Masked and Protected if appropriate):
SIMPLEOTA_BASE_URLSIMPLEOTA_PROJECT_IDSIMPLEOTA_TOKEN
Minimal job¶
upload-firmware:
image: curlimages/curl:8.10.1
rules:
- if: $CI_COMMIT_TAG =~ /^v/
- if: $CI_PIPELINE_SOURCE == "web"
script:
- |
MANIFEST_JSON=$(cat <<EOF
{
"framework": "arduino",
"chip_family": "esp32",
"board_id": "esp32dev",
"partition_profile": "default_4mb",
"nvs_schema_version": 1,
"security_mode": "basic"
}
EOF
)
curl --fail-with-body \
-X POST "${SIMPLEOTA_BASE_URL}/api/v1/projects/${SIMPLEOTA_PROJECT_ID}/artifacts/" \
-H "Authorization: Bearer ${SIMPLEOTA_TOKEN}" \
-F "manifest=${MANIFEST_JSON}" \
-F "[email protected]"
Signed uploads¶
For signed firmware, define one more variable
(Masked): SIMPLEOTA_SIGNING_KEY, containing the private key PEM. The
curlimages/curl image has no OpenSSL, so use a base image that does:
upload-firmware-signed:
image: alpine:3.21
rules:
- if: $CI_COMMIT_TAG =~ /^v/
before_script:
- apk add --no-cache curl openssl
script:
- printf '%s' "$SIMPLEOTA_SIGNING_KEY" > private.pem
- openssl pkeyutl -sign -inkey private.pem -rawin -in firmware.bin | openssl base64 -A > firmware.sig.b64
- rm -f private.pem
- |
MANIFEST_JSON=$(cat <<EOF
{
"framework": "arduino",
"version_label": "${CI_COMMIT_TAG}",
"chip_family": "esp32",
"board_id": "esp32dev",
"partition_profile": "default_4mb",
"nvs_schema_version": 1,
"security_mode": "signed",
"signing_metadata": {
"key_id": "prod-2026",
"algorithm": "ed25519",
"signature": "$(cat firmware.sig.b64)"
}
}
EOF
)
curl --fail-with-body \
-X POST "${SIMPLEOTA_BASE_URL}/api/v1/projects/${SIMPLEOTA_PROJECT_ID}/artifacts/" \
-H "Authorization: Bearer ${SIMPLEOTA_TOKEN}" \
-F "manifest=${MANIFEST_JSON}" \
-F "[email protected]"
Replace prod-2026 with your project's key id. The signature must cover
the final, shippable bytes: with ESP32 Secure Boot, sign after
espsecure (see Secure Boot notes).
If your build job runs in an earlier stage, mark the binary as an artifact so this stage can pick it up: