<?php

use Illuminate\Support\Facades\File;

/**
 * Die root-eigene Hälfte, als Text gelesen.
 *
 * Ausführen lässt sie sich hier nicht — sie will einen Wirt mit sshd, einer
 * laufenden Anlage und einem Auschecken unter /opt/clupilot. Was ein Test
 * trotzdem festhalten kann, sind die Entscheidungen, die in ihr stecken und
 * die man beim nächsten Anfassen versehentlich zurücknimmt.
 *
 * Nachbar, nicht Ersatz: tests/Feature/HostStepTest.php prüft den Helfer als
 * Ganzes — dass er root gehört, dass sudoers je eine feste Kommandozeile nennt,
 * dass der Vertrag zu update.sh passt. Hier steht nur, was DIESEN Schritt
 * ausmacht.
 */
function installAgent(): string
{
    return File::get(base_path('deploy/install-agent.sh'));
}

it('erhoeht den Vertrag, damit Bestandsserver ueberhaupt erfahren, dass es den Schritt gibt', function () {
    // Ein neuer Schritt nuetzt auf einem Server nichts, der noch den alten
    // Helfer traegt — und still nutzlos ist die Fehlerart, fuer die update.sh
    // seine Vertragspruefung hat.
    expect(installAgent())->toContain('CONTRACT=3')
        ->and(installAgent())->toContain('install-server-terminal)');
});

it('gibt dem Dienstkonto KEINEN sudo-Weg, sich selbst einen Root-Schluessel einzutragen', function () {
    $script = installAgent();

    // Der sudoers-Block nennt genau die Schritte, die das Dienstkonto anstossen
    // darf. `install-server-terminal` schreibt nach /root/.ssh/authorized_keys;
    // stuende er dort, koennte eine uebernommene Anwendung sich jederzeit
    // selbst root geben — Kennung neu erzeugen, Schritt anstossen, fertig.
    $sudoers = str($script)->after('/etc/sudoers.d/clupilot-host-step <<EOF')->before('EOF')->toString();

    expect($sudoers)->toContain('ensure-rsync')
        ->and($sudoers)->toContain('apply-proxy-hosts')
        ->and($sudoers)->not->toContain('install-server-terminal');
});

it('nimmt genau eine ssh-ed25519-Zeile an und nichts sonst', function () {
    $script = installAgent();

    // Die beiden Haelften der Pruefung: „genau eine Zeile" und „sieht aus wie
    // ein Schluessel". Ohne die erste waere ein Zeilenumbruch im Wert ein
    // zweiter Schluessel; ohne die zweite genuegte irgendein Text.
    expect($script)->toContain('-eq 1 ]] \\')
        ->and($script)->toContain('^ssh-ed25519\ [A-Za-z0-9+/]+=*');
});

it('schreibt die Optionsliste selbst, statt sie sich reichen zu lassen', function () {
    // `from` bindet den Schluessel an das Container-Netz, `restrict` nimmt ihm
    // alles ausser einer Sitzung, `pty` gibt das eine zurueck, ohne das ein
    // Terminal keines ist. Kaeme diese Liste aus der Anwendung, waere aus „die
    // Anwendung nennt ihren Schluessel" ein „die Anwendung schreibt in
    // authorized_keys" geworden.
    expect(installAgent())->toContain('from="%s",restrict,pty %s');
});

it('bildet den Fingerabdruck in CluPilots Form, nicht in der von OpenSSH', function () {
    $script = installAgent();

    // Gehasht wird die Zeichenkette "<algorithmus> <base64-blob>" — siehe
    // fingerprints() in docker/terminal/bridge.py. `ssh-keygen -lf` gaebe den
    // bekannten OpenSSH-Fingerabdruck und damit bei JEDEM Verbindungsversuch
    // eine Abweichung.
    expect($script)->toContain("printf '%s %s'")
        ->and($script)->toContain('openssl dgst -sha256 -binary')
        ->and($script)->not->toContain('ssh-keygen -lf');
});

it('haelt Adresse und Fingerabdruck dort fest, wo die Anwendung sie liest', function () {
    expect(installAgent())->toContain('storage/app/deploy/server-terminal.json')
        ->and(installAgent())->toContain('"installed_at"');
});
