Serve Woodpecker pipeline configs from the engine (/build/config)

This commit is contained in:
2026-08-06 01:14:22 +02:00
parent b64c82aa13
commit 1c7498ca4a
15 changed files with 1232 additions and 0 deletions
@@ -0,0 +1,40 @@
require "erb"
module WarpEngine
# A /build/config platform-template-jeinek renderelése: a pipeline-logika
# a lib/warp_engine/ci_templates/<platform>.yaml.erb fájlokban él, a
# platformonkénti builder image-eket a WarpEngine.config.ci_platforms adja.
class CiConfigService
PLATFORM_FORMAT = /\A[a-z0-9_-]+\z/
# A renderelt pipeline YAML, vagy nil, ha a platform nem kiszolgált.
def render(platform:, name:, update_server:)
platform = platform.to_s
return nil unless platform.match?(PLATFORM_FORMAT)
spec = platform_spec(platform)
return nil if spec.nil?
path = templates_dir.join("#{platform}.yaml.erb")
return nil unless path.exist?
ERB.new(path.read, trim_mode: "-").result_with_hash(
name: name.to_s,
update_server: update_server.to_s,
builder: spec[:builder],
exporter: spec[:exporter]
)
end
private
def platform_spec(platform)
spec = WarpEngine.config.ci_platforms.stringify_keys[platform]
spec&.symbolize_keys
end
def templates_dir
WarpEngine::Engine.root.join("lib", "warp_engine", "ci_templates")
end
end
end
@@ -0,0 +1,90 @@
require "openssl"
require "base64"
require "net/http"
module WarpEngine
# A Woodpecker configuration-extension kéréseinek httpsig-ellenőrzése
# (draft-cavage http-signatures, ed25519). A szerver az aláírt headerek
# listáját a Signature headerben küldi — tipikusan "(request-target) date".
class CiSignatureVerifier
SIGNATURE_PARAM = /(\w+)="([^"]*)"/
@key_cache = {}
@key_mutex = Mutex.new
class << self
# A letöltött kulcs process-szinten cache-elt (URL-enként).
def fetch_public_key(url)
@key_mutex.synchronize do
@key_cache[url] ||= Net::HTTP.get(URI.parse(url))
end
end
def reset_key_cache!
@key_mutex.synchronize { @key_cache = {} }
end
end
def initialize(request)
@request = request
end
def valid?
pem = public_key_pem
if pem.blank?
Rails.logger.error("[CiSignatureVerifier] nincs ci_extension_public_key(_url) konfigurálva — kérés elutasítva")
return false
end
params = signature_params
return false if params.nil? || params["signature"].blank?
signing_string = build_signing_string(params.fetch("headers", "date"))
return false if signing_string.nil?
key = OpenSSL::PKey.read(pem)
key.verify(nil, Base64.decode64(params["signature"]), signing_string)
rescue OpenSSL::PKey::PKeyError, ArgumentError => e
Rails.logger.error("[CiSignatureVerifier] #{e.class}: #{e.message}")
false
end
private
def public_key_pem
config = WarpEngine.config
return config.ci_extension_public_key if config.ci_extension_public_key.present?
return nil if config.ci_extension_public_key_url.blank?
self.class.fetch_public_key(config.ci_extension_public_key_url)
rescue StandardError => e
Rails.logger.error("[CiSignatureVerifier] kulcs-letöltés sikertelen: #{e.class}: #{e.message}")
nil
end
# A Signature header (vagy az "Authorization: Signature ..." forma) paraméterei.
def signature_params
header = @request.headers["Signature"].presence
if header.nil?
auth = @request.headers["Authorization"].to_s
header = auth.delete_prefix("Signature ") if auth.start_with?("Signature ")
end
return nil if header.blank?
header.scan(SIGNATURE_PARAM).to_h
end
def build_signing_string(headers_list)
lines = headers_list.split(" ").map do |name|
if name == "(request-target)"
"(request-target): #{@request.request_method.downcase} #{@request.fullpath}"
else
value = @request.headers[name]
return nil if value.nil?
"#{name.downcase}: #{value}"
end
end
lines.join("\n")
end
end
end