save progress
This commit is contained in:
@@ -5447,6 +5447,11 @@ internal static class CommandFactory
|
||||
var ociVerify = BuildOciVerifyCommand(services, verboseOption, cancellationToken);
|
||||
attest.Add(ociVerify); // stella attest oci-verify --image ...
|
||||
|
||||
// Sprint: SPRINT_20260102_002_BE_intoto_link_generation (IT-023)
|
||||
// in-toto link creation
|
||||
var link = BuildInTotoLinkCommand(services, verboseOption, cancellationToken);
|
||||
attest.Add(link); // stella attest link --step ...
|
||||
|
||||
return attest;
|
||||
}
|
||||
|
||||
@@ -5687,6 +5692,134 @@ internal static class CommandFactory
|
||||
return ociVerify;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds 'attest link' subcommand for creating in-toto link attestations.
|
||||
/// Sprint: SPRINT_20260102_002_BE_intoto_link_generation (IT-023)
|
||||
/// </summary>
|
||||
private static Command BuildInTotoLinkCommand(
|
||||
IServiceProvider services,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// Step name (required)
|
||||
var stepNameOption = new Option<string>("--step", new[] { "-s" })
|
||||
{
|
||||
Description = "Name of the supply chain step (e.g., 'scan', 'build', 'sign')",
|
||||
Required = true
|
||||
};
|
||||
|
||||
// Materials (inputs)
|
||||
var materialsOption = new Option<string[]?>("--material", new[] { "-m" })
|
||||
{
|
||||
Description = "Material (input) in format 'uri' or 'uri=sha256:digest'. Can be specified multiple times.",
|
||||
AllowMultipleArgumentsPerToken = true
|
||||
};
|
||||
|
||||
// Products (outputs)
|
||||
var productsOption = new Option<string[]?>("--product", new[] { "-p" })
|
||||
{
|
||||
Description = "Product (output) in format 'uri' or 'uri=sha256:digest'. Can be specified multiple times.",
|
||||
AllowMultipleArgumentsPerToken = true
|
||||
};
|
||||
|
||||
// Command
|
||||
var commandOption = new Option<string[]?>("--command", new[] { "-c" })
|
||||
{
|
||||
Description = "Command that was executed. Can be specified multiple times for each arg.",
|
||||
AllowMultipleArgumentsPerToken = true
|
||||
};
|
||||
|
||||
// Return value
|
||||
var returnValueOption = new Option<int?>("--return-value", new[] { "-r" })
|
||||
{
|
||||
Description = "Return value of the command (exit code). Default: 0"
|
||||
};
|
||||
|
||||
// Environment variables to capture
|
||||
var envOption = new Option<string[]?>("--env", new[] { "-e" })
|
||||
{
|
||||
Description = "Environment variable to include in format 'NAME=value'. Can be specified multiple times.",
|
||||
AllowMultipleArgumentsPerToken = true
|
||||
};
|
||||
|
||||
// Signing options
|
||||
var keyOption = new Option<string?>("--key", new[] { "-k" })
|
||||
{
|
||||
Description = "Key identifier or path for signing"
|
||||
};
|
||||
|
||||
var keylessOption = new Option<bool>("--keyless")
|
||||
{
|
||||
Description = "Use keyless (OIDC) signing via Sigstore Fulcio"
|
||||
};
|
||||
|
||||
var rekorOption = new Option<bool>("--rekor")
|
||||
{
|
||||
Description = "Submit link to Rekor transparency log"
|
||||
};
|
||||
|
||||
// Output options
|
||||
var outputOption = new Option<string?>("--output", new[] { "-o" })
|
||||
{
|
||||
Description = "Output path for the signed in-toto link envelope"
|
||||
};
|
||||
|
||||
var formatOption = new Option<string?>("--format", new[] { "-f" })
|
||||
{
|
||||
Description = "Output format: dsse (default), json (link only), sigstore-bundle"
|
||||
};
|
||||
|
||||
var link = new Command("link", "Create a signed in-toto link attestation for a supply chain step")
|
||||
{
|
||||
stepNameOption,
|
||||
materialsOption,
|
||||
productsOption,
|
||||
commandOption,
|
||||
returnValueOption,
|
||||
envOption,
|
||||
keyOption,
|
||||
keylessOption,
|
||||
rekorOption,
|
||||
outputOption,
|
||||
formatOption,
|
||||
verboseOption
|
||||
};
|
||||
|
||||
link.SetAction(async (parseResult, ct) =>
|
||||
{
|
||||
var stepName = parseResult.GetValue(stepNameOption) ?? string.Empty;
|
||||
var materials = parseResult.GetValue(materialsOption) ?? Array.Empty<string>();
|
||||
var products = parseResult.GetValue(productsOption) ?? Array.Empty<string>();
|
||||
var command = parseResult.GetValue(commandOption) ?? Array.Empty<string>();
|
||||
var returnValue = parseResult.GetValue(returnValueOption) ?? 0;
|
||||
var env = parseResult.GetValue(envOption) ?? Array.Empty<string>();
|
||||
var keyId = parseResult.GetValue(keyOption);
|
||||
var keyless = parseResult.GetValue(keylessOption);
|
||||
var useRekor = parseResult.GetValue(rekorOption);
|
||||
var output = parseResult.GetValue(outputOption);
|
||||
var format = parseResult.GetValue(formatOption) ?? "dsse";
|
||||
var verbose = parseResult.GetValue(verboseOption);
|
||||
|
||||
return await CommandHandlers.HandleAttestLinkAsync(
|
||||
services,
|
||||
stepName,
|
||||
materials,
|
||||
products,
|
||||
command,
|
||||
returnValue,
|
||||
env,
|
||||
keyId,
|
||||
keyless,
|
||||
useRekor,
|
||||
output,
|
||||
format,
|
||||
verbose,
|
||||
cancellationToken);
|
||||
});
|
||||
|
||||
return link;
|
||||
}
|
||||
|
||||
private static Command BuildRiskProfileCommand(Option<bool> verboseOption, CancellationToken cancellationToken)
|
||||
{
|
||||
_ = cancellationToken;
|
||||
|
||||
Reference in New Issue
Block a user