Merge pull request 'fix(ci): the cleanup script forced TLS onto a plaintext endpoint (#324)' (#339) from fix/324-cleanup-honours-scheme into main
Linting / lint (push) Successful in 2m50s
SonarQube Analysis / sonarqube (push) Failing after 31m9s

Reviewed-on: #339
This commit was merged in pull request #339.
This commit is contained in:
2026-09-10 07:19:47 -05:00
+39 -3
View File
@@ -11,7 +11,8 @@
* harmless one.
*
* Environment:
* GITEA_HOST origin of the instance, e.g. https://gitea.example.com
* GITEA_HOST origin of the instance, scheme included, e.g.
* https://gitea.example.com or http://gitea:3000
* GITEA_REPO "owner/name"
* GITEA_ACCESS_TOKEN token permitted to delete runs
* KEEP_DAYS keep runs newer than this many days (default 7)
@@ -19,6 +20,7 @@
*/
const https = require('https');
const http = require('http');
const { URL } = require('url');
const HOST = process.env.GITEA_HOST;
@@ -39,12 +41,41 @@ if (!Number.isFinite(KEEP_DAYS) || KEEP_DAYS < 0) {
}
const origin = new URL(HOST);
/**
* The transport GITEA_HOST actually asks for, rather than the one assumed.
*
* This was hardcoded to https, which worked when the host was typed by hand and
* failed the moment the workflow started taking it from `github.server_url`.
* Inside the runner that is the address act_runner reaches Gitea on, which here
* is plain HTTP on a container port — and a TLS handshake sent to a plaintext
* port does not fail as a connection error. It fails as:
*
* write EPROTO ... ssl3_get_record:wrong version number
*
* which reads like a TLS misconfiguration and sends you looking at certificates
* and protocol versions. It is neither. The server answered in cleartext and
* OpenSSL tried to parse that as a TLS record.
*
* So the scheme is honoured rather than guessed, and the default port follows
* from it. Anything other than the two is refused up front: this script only
* speaks HTTP, and a URL naming some other scheme is a mistake worth reporting
* as one instead of failing later inside a request.
*/
if (origin.protocol !== 'https:' && origin.protocol !== 'http:') {
console.error(`GITEA_HOST must be an http or https URL, got ${HOST}`);
process.exit(1);
}
const secure = origin.protocol === 'https:';
const transport = secure ? https : http;
const PORT = origin.port || (secure ? 443 : 80);
const BASE = `/api/v1/repos/${REPO}/actions/runs`;
function call(method, path) {
return new Promise((resolve, reject) => {
const req = https.request(
{ hostname: origin.hostname, port: origin.port || 443, path, method, headers: { Authorization: `token ${TOKEN}` } },
const req = transport.request(
{ hostname: origin.hostname, port: PORT, path, method, headers: { Authorization: `token ${TOKEN}` } },
(res) => {
let body = '';
res.on('data', (d) => (body += d));
@@ -126,6 +157,11 @@ function selectDoomed(runs, cutoffMs) {
}
(async () => {
// Printed before the first request rather than after it succeeds. A transport
// failure here says nothing about where it was pointed, and the last one cost
// a round trip to find out that the answer was "somewhere plaintext".
console.log(`endpoint : ${origin.protocol}//${origin.hostname}:${PORT}`);
const runs = await listAllRuns();
const cutoffMs = Date.now() - KEEP_DAYS * 86400000;
const { doomed, kept } = selectDoomed(runs, cutoffMs);