A kódbázis kommentek nélkül marad
Kérésre: minden magyarázó komment kikerült a forrásfájlokból — 89 Ruby, 16 TypeScript, 14 Vue, plusz a CSS/JS/CJS. Nem soralapú kereséssel: a Ruby-t a Ripper tokenizálta, a JS/TS/CSS-t állapotgép járta végig, hogy az URL-ekben, reguláris kifejezésekben és heredocokban álló // és # jelek helyükön maradjanak. Három komment maradt, mert nélkülük nem indul a kód: az entrypoint.sh shebangja, a vite-env.d.ts hármas perjeles referenciája, és a sanitize teszt @vitest-environment direktívája (ez utóbbi a magyarázó része nélkül). Egy helyen kódot is kellett írni: a CommandBlock másolás-hibaágán a komment volt a catch egyetlen tartalma, és üres blokkot az eslint nem enged — a copied jelző visszaállítása került a helyére. A yaml, Dockerfile, Makefile, erb és markdown fájlokat nem érintettem. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,2 @@
|
||||
# Test-only: plays the ApplicationToken owner role in the dummy app.
|
||||
class TestOwner < ActiveRecord::Base
|
||||
end
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# Test-only: plays the ApplicationToken owner role (AdminUser in the host).
|
||||
class CreateTestOwners < ActiveRecord::Migration[8.1]
|
||||
def change
|
||||
create_table :test_owners, id: { type: :bigint, unsigned: true },
|
||||
|
||||
@@ -1,15 +1,3 @@
|
||||
# This file is auto-generated from the current state of the database. Instead
|
||||
# of editing this file, please use the migrations feature of Active Record to
|
||||
# incrementally modify your database, and then regenerate this schema definition.
|
||||
#
|
||||
# This file is the source Rails uses to define your schema when running `bin/rails
|
||||
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
|
||||
# be faster and is potentially less error prone than running all of your
|
||||
# migrations from scratch. Old migrations may fail to apply correctly if those
|
||||
# migrations use external dependencies or application code.
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.1].define(version: 2026_08_19_093412) do
|
||||
create_table "application_tokens", id: { type: :bigint, unsigned: true }, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
|
||||
t.datetime "created_at", precision: 3
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# TestOwner exists only in the dummy app — host-side usage must override the
|
||||
# owner (e.g. owner: create(:admin_user)).
|
||||
FactoryBot.define do
|
||||
factory :test_owner, class: "TestOwner" do
|
||||
name { "test owner" }
|
||||
|
||||
@@ -41,7 +41,6 @@ RSpec.describe WarpEngine::Storage do
|
||||
expect(adapter.file?("missing.zip")).to be(false)
|
||||
end
|
||||
|
||||
# The path traversal guard has to survive the move behind the adapter.
|
||||
it "refuses paths escaping the container" do
|
||||
outside = File.join(Dir.mktmpdir, "secret.txt")
|
||||
File.write(outside, "nope")
|
||||
|
||||
@@ -1,25 +1,8 @@
|
||||
require "rails_helper"
|
||||
|
||||
# The engine appends its `db/migrate` to the host's migration paths instead of copying
|
||||
# migrations into the host, so the two share **one** version namespace. A collision does
|
||||
# not fail politely somewhere in the engine: it stops the host's `db:migrate` before it
|
||||
# runs anything, for the whole application.
|
||||
#
|
||||
# That is exactly what happened to `device_grants`. It was numbered 20260819000001 — a
|
||||
# hand-picked round number — and the catalog API had written
|
||||
# `20260819000001_carry_the_store_config_in_the_registry` on the same day with the same
|
||||
# habit. Neither repository could see the other's number.
|
||||
#
|
||||
# The defence is that engine migrations carry a real second-resolution timestamp, which
|
||||
# nobody hand-writes and nothing rounds to. This is the test that says so.
|
||||
RSpec.describe "Engine migrations" do
|
||||
# `202608050000 01`-style numbers: a date, then zeros, then a counter. Rails generates
|
||||
# `20260819093412`; a person types this.
|
||||
ROUND_VERSION = /\A\d{8}0{4}\d{2}\z/
|
||||
|
||||
# Numbered before this file existed and already deployed everywhere. Renumbering a
|
||||
# migration that has run is worse than the risk it carries, so they are named here
|
||||
# rather than quietly excluded by a rule that would also excuse the next one.
|
||||
GRANDFATHERED = %w[
|
||||
20260805000001
|
||||
20260805000003
|
||||
@@ -49,14 +32,6 @@ RSpec.describe "Engine migrations" do
|
||||
"timestamp — `date -u +%Y%m%d%H%M%S` — not a hand-picked round number."
|
||||
end
|
||||
|
||||
# A table created by BOTH the install template and one of our own migrations is a
|
||||
# second CREATE TABLE for the same name in whatever host installs us — the template
|
||||
# runs, then the appended engine migration runs, and the second one fails.
|
||||
#
|
||||
# `application_tokens` is exactly that, and has been since before this file existed:
|
||||
# every host installing today has to delete that block from its generated copy by
|
||||
# hand, which is what teletype-orbit's own migration says in its header. It is
|
||||
# grandfathered here rather than quietly excused, so the list can only shrink.
|
||||
it "does not create a table the install generator also creates" do
|
||||
template = WarpEngine::Engine.root.join(
|
||||
"lib/generators/warp_engine/install/templates/create_warp_engine_tables.rb"
|
||||
|
||||
@@ -60,9 +60,6 @@ RSpec.describe WarpEngine::Pipeline do
|
||||
it { is_expected.to belong_to(:software).optional }
|
||||
end
|
||||
|
||||
# A software has one pipeline. Two pipelines pointing at the same one is not an error
|
||||
# the database catches, it is a link that silently does nothing — so the newest
|
||||
# assignment takes it, and says what it took it from.
|
||||
describe "assigning a software another pipeline already has" do
|
||||
it "moves the link and leaves the other pipeline without one" do
|
||||
software = create(:software)
|
||||
|
||||
@@ -6,10 +6,9 @@ RSpec.describe WarpEngine::Software, type: :model do
|
||||
it { should validate_presence_of(:name) }
|
||||
it { should validate_presence_of(:title) }
|
||||
it { should validate_presence_of(:platform) }
|
||||
# MySQL utf8mb4_0900_ai_ci collation: az egyediség DB-szinten case-insensitive
|
||||
|
||||
it { should validate_uniqueness_of(:name).case_insensitive }
|
||||
|
||||
# a törlést a DB-szintű ON DELETE CASCADE végzi, a modellen nincs dependent opció
|
||||
it { should have_many(:releases) }
|
||||
it { should have_many(:external_links) }
|
||||
it { should have_many(:software_images).dependent(:destroy) }
|
||||
|
||||
@@ -11,7 +11,6 @@ rescue ActiveRecord::PendingMigrationError => e
|
||||
abort e.to_s.strip
|
||||
end
|
||||
|
||||
# A factory_bot_rails a dummy app gyökerében keresne; a factory-k az engine spec/ alatt élnek
|
||||
FactoryBot.definition_file_paths = [ File.expand_path("factories", __dir__) ]
|
||||
FactoryBot.reload
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ RSpec.describe "Build configs endpoint", type: :request do
|
||||
allow(WarpEngine.config).to receive(:ci_extension_public_key).and_return(signing_key.public_to_pem)
|
||||
end
|
||||
|
||||
# Woodpecker 3.x-style RFC 9421 signature over @request-target + content-digest.
|
||||
def signed_headers(body, path: "/build/config", digest_body: nil)
|
||||
digest = "sha-256=:#{Digest::SHA256.base64digest(digest_body || body)}:"
|
||||
inner = %{("@request-target" "content-digest");created=#{Time.now.to_i};alg="ed25519"}
|
||||
@@ -33,7 +32,6 @@ RSpec.describe "Build configs endpoint", type: :request do
|
||||
}
|
||||
end
|
||||
|
||||
# Legacy draft-cavage signature (single Signature header).
|
||||
def cavage_signed_headers(method: "post", path: "/build/config")
|
||||
date = Time.now.httpdate
|
||||
signing_string = "(request-target): #{method} #{path}\ndate: #{date}"
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
require "rails_helper"
|
||||
|
||||
# Signing a client in, end to end: the client asks for a code, a person approves it on
|
||||
# the host's page, the client's next poll carries the token away, and the token then
|
||||
# works as a bearer credential on the read-only API.
|
||||
RSpec.describe "Device sign-in", type: :request do
|
||||
let(:owner) { create(:test_owner) }
|
||||
|
||||
# The identity seam is off by default. Configuring the subject class is what turns
|
||||
# the whole flow on — including whether it exists at all.
|
||||
def configure_identity!(verification: "/devices")
|
||||
allow(WarpEngine.config).to receive(:access_token_owner_class).and_return("TestOwner")
|
||||
allow(WarpEngine.config).to receive(:identity_verification_url).and_return(verification)
|
||||
@@ -37,7 +32,7 @@ RSpec.describe "Device sign-in", type: :request do
|
||||
expect(response).to have_http_status(:ok)
|
||||
json = JSON.parse(response.body)
|
||||
expect(json["deviceCode"]).to be_present
|
||||
# Grouped and free of I/O/0/1, because it is typed by hand into a browser.
|
||||
|
||||
expect(json["userCode"]).to match(/\A[A-HJ-NP-Z2-9]{4}-[A-HJ-NP-Z2-9]{4}\z/)
|
||||
expect(json["verificationUrl"]).to eq("http://www.example.com/devices")
|
||||
expect(json["interval"]).to eq(5)
|
||||
@@ -64,8 +59,6 @@ RSpec.describe "Device sign-in", type: :request do
|
||||
expect(body["token"]).to be_present
|
||||
end
|
||||
|
||||
# The plain token is never stored, so it cannot be handed out twice. A client that
|
||||
# loses it starts again — which is cheaper than a database full of live secrets.
|
||||
it "does not repeat the token on a second poll" do
|
||||
post "/api/auth/device", params: { client_name: "laptop" }
|
||||
json = JSON.parse(response.body)
|
||||
@@ -145,8 +138,6 @@ RSpec.describe "Device sign-in", type: :request do
|
||||
expect(record.scopes).to eq([ "catalog" ])
|
||||
end
|
||||
|
||||
# A publishing token must not become a client token by accident, and vice versa:
|
||||
# the scope is what separates them, and the catalog endpoint requires its own.
|
||||
it "is not accepted as a publishing credential" do
|
||||
token
|
||||
|
||||
@@ -197,8 +188,6 @@ RSpec.describe "Device sign-in", type: :request do
|
||||
end
|
||||
end
|
||||
|
||||
# A browser carries a session, not a bearer token, and the engine has no idea what a
|
||||
# session is. A host that wants its signed-in visitors recognised says how.
|
||||
describe "the host's own subject resolver" do
|
||||
let(:seen) { [] }
|
||||
let(:policy) do
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
require "rails_helper"
|
||||
|
||||
# The descriptor is how a client stops being built for one particular store: everything
|
||||
# it used to have compiled in — is there a sign-in, where does it live, can titles be
|
||||
# gated — is answered here instead.
|
||||
RSpec.describe "GET /api/service", type: :request do
|
||||
after { WarpEngine::AccessPolicy.reset! }
|
||||
|
||||
@@ -53,8 +50,6 @@ RSpec.describe "GET /api/service", type: :request do
|
||||
expect(auth["device"]["interval"]).to eq(5)
|
||||
end
|
||||
|
||||
# A host that configured a bare path should not have to know its own hostname; one
|
||||
# that put the approval page on another domain should keep it.
|
||||
it "makes a configured path absolute against the request" do
|
||||
get "/api/service"
|
||||
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
require "rails_helper"
|
||||
|
||||
# Every response the engine serves carries the version that served it, so a client can
|
||||
# branch on the engine's age without asking a separate endpoint for it.
|
||||
RSpec.describe "the WarpEngine-Version header", type: :request do
|
||||
# The controller writes the name as a literal so that it cannot depend on a constant a
|
||||
# half-updated deploy might not have. This is what keeps the two in step.
|
||||
it "is the name the constant documents" do
|
||||
expect(WarpEngine::VERSION_HEADER).to eq("WarpEngine-Version")
|
||||
end
|
||||
@@ -18,9 +14,6 @@ RSpec.describe "the WarpEngine-Version header", type: :request do
|
||||
expect(response.headers["WarpEngine-Version"]).to eq(WarpEngine::VERSION)
|
||||
end
|
||||
|
||||
# The one a client needs most: something came back wrong, and it wants to know whether
|
||||
# the engine on the other end is old enough to explain it. `rescue_from` never reaches
|
||||
# an after_action, which is why the header is set before the action runs.
|
||||
it "is on an error response" do
|
||||
get "/api/image/999999"
|
||||
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
require "rails_helper"
|
||||
require "tmpdir"
|
||||
|
||||
# The access seam, from both sides: what the catalog says about a title, and whether an
|
||||
# artifact is handed over. The load-bearing case is the *default* one — a catalog with
|
||||
# no policy configured has to behave exactly as it did before this existed.
|
||||
RSpec.describe "The access policy" do
|
||||
let(:tmpdir) { Dir.mktmpdir }
|
||||
|
||||
# A policy that gates everything except what the subject is named after. Small enough
|
||||
# to read, and it exercises every method of the contract.
|
||||
let(:gating_policy) do
|
||||
Class.new do
|
||||
def initialize(open_name) = @open_name = open_name
|
||||
@@ -153,8 +148,6 @@ RSpec.describe "The access policy" do
|
||||
|
||||
before { allow(WarpEngine.config).to receive(:access_policy).and_return(broken_policy) }
|
||||
|
||||
# The direction of the failure is the point. A broken gatekeeper must not become an
|
||||
# open one: an empty catalog is recoverable, a paid title given away is not.
|
||||
it "empties the catalog rather than leaking it" do
|
||||
create(:software, status: "released")
|
||||
|
||||
|
||||
@@ -64,8 +64,6 @@ RSpec.describe WarpEngine::PublishService do
|
||||
allow(WarpEngine::Platforms::Tic80::Service).to receive(:new).and_return(mock_service)
|
||||
end
|
||||
|
||||
# The host reacts to a new build through this event instead of hanging a
|
||||
# callback on the Release model.
|
||||
it "emits warp_engine.publish with the release in the payload" do
|
||||
payloads = []
|
||||
ActiveSupport::Notifications.subscribe(described_class::NOTIFICATION) do |*, payload|
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
require "rails_helper"
|
||||
require "tmpdir"
|
||||
|
||||
# The serving side (FileService, DownloadService) goes through the storage
|
||||
# adapter. With :local nothing changes; with a custom adapter the same call
|
||||
# can hand back a redirect instead of a file.
|
||||
RSpec.describe "Serving through the storage adapter" do
|
||||
let(:tmpdir) { Dir.mktmpdir }
|
||||
|
||||
# Minimal adapter answering the documented contract.
|
||||
let(:signing_adapter) do
|
||||
Class.new do
|
||||
def file?(_relative) = true
|
||||
|
||||
Reference in New Issue
Block a user