ExportKeyringSecretCommand.java

// SPDX-License-Identifier: Apache-2.0
// Copyright 2026 Egothor
// Copyright 2026 Accenture
package org.egothor.methodatlas.evidence;

import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Path;

/**
 * CLI command handler for the {@code -export-keyring-secret} mode, which prints
 * an encrypted keyring as a single text value for a CI/CD platform secret.
 *
 * <h2>Usage</h2>
 * <pre>{@code
 * methodatlas -export-keyring-secret <keyring-file> > keyring.secret
 * }</pre>
 *
 * <p>
 * The output is the keyring bundle described in {@link KeyringFiles}: the
 * encrypted store and its {@code .nonce} sidecar, Base64-encoded under a header
 * line. It is consumed by {@code -evidence-pack-keyring-env}. The keyring stays
 * encrypted inside the bundle, so no password is needed to export it and the
 * password must be stored as a separate secret. The bundle is printed to
 * {@code stdout}; guidance goes to {@code stderr} so redirection captures only
 * the secret.
 * </p>
 *
 * @see KeyringFiles#exportBundle(Path)
 * @since 6.2.0
 */
public final class ExportKeyringSecretCommand {

    /** Mode flag that selects this command. */
    public static final String FLAG_EXPORT_KEYRING_SECRET = "-export-keyring-secret";

    /** Exit code returned on success. */
    private static final int EXIT_OK = 0;

    /** Exit code returned when the arguments are invalid. */
    private static final int EXIT_BAD_ARGS = 2;

    /** Prevents instantiation. */
    private ExportKeyringSecretCommand() {
    }

    /**
     * Parses {@code -export-keyring-secret} arguments and prints the bundle.
     *
     * @param args full command-line arguments, including the mode flag and its value
     * @param out  writer that receives the bundle text
     * @return {@code 0} on success, {@code 2} when the keyring argument is missing
     * @throws IOException if the keyring cannot be read or is not an encrypted keyring
     */
    public static int run(String[] args, PrintWriter out) throws IOException {
        Path keyringFile = null;
        for (int i = 0; i < args.length - 1; i++) {
            if (FLAG_EXPORT_KEYRING_SECRET.equals(args[i])) {
                keyringFile = Path.of(args[i + 1]);
            }
        }
        if (keyringFile == null) {
            System.err.println("export-keyring-secret: missing keyring file after " + FLAG_EXPORT_KEYRING_SECRET);
            System.err.println("Usage: " + FLAG_EXPORT_KEYRING_SECRET + " <keyring-file>");
            return EXIT_BAD_ARGS;
        }
        out.print(KeyringFiles.exportBundle(keyringFile));
        out.flush();
        System.err.println("Store the text above as a CI secret (e.g. METHODATLAS_KEYRING) and the keyring "
                + "password as a second secret (e.g. METHODATLAS_KEYRING_PASSWORD); then sign with "
                + "-evidence-pack-keyring-env METHODATLAS_KEYRING.");
        return EXIT_OK;
    }
}