podman/example/secrets_workflow_example.dart

159 lines
4.3 KiB
Dart

import 'dart:io';
import 'package:podman/podman.dart';
Future<void> main(List<String> args) async {
if (args.contains('--help') || args.contains('-h')) {
_printUsage();
return;
}
final name =
_readOption(args, 'name') ?? (args.isNotEmpty ? args.first : null);
final rawValue = _readOption(args, 'value');
final filePath = _readOption(args, 'file');
final driver = _readOption(args, 'driver');
final showSecret = args.contains('--show-secret');
final cleanup = args.contains('--cleanup');
final replace = args.contains('--replace');
final ignore = args.contains('--ignore');
if (name == null || name.isEmpty) {
stderr.writeln('Missing secret name.');
_printUsage();
exitCode = 64;
return;
}
final value = await _resolveSecretValue(
rawValue: rawValue,
filePath: filePath,
);
if (value == null || value.isEmpty) {
stderr.writeln(
'Provide a secret value via --value, --file, or PODMAN_EXAMPLE_SECRET.',
);
_printUsage();
exitCode = 64;
return;
}
final labels = _readKeyValueOptions(args, 'label');
final driverOptions = _readKeyValueOptions(args, 'driver-opt');
final client = PodmanClient();
try {
final created = await client.createSecret(
SecretCreateOptions(
name: name,
data: value,
driver: driver,
labels: labels,
driverOptions: driverOptions,
replace: replace,
ignore: ignore,
),
);
print('Created/updated secret "$name" with id ${created.id}.');
final exists = await client.secretExists(name);
print('Secret exists: $exists');
final details = await client.inspectSecret(name, showSecret: showSecret);
print('Driver: ${details.driver.isEmpty ? 'unknown' : details.driver}');
print('Labels: ${details.labels.isEmpty ? '(none)' : details.labels}');
print('Updated: ${details.updatedAt?.toIso8601String() ?? 'unknown'}');
if (showSecret) {
print('Secret payload length: ${details.secretData.length}');
}
final allSecrets = await client.listSecrets();
print('Total secrets visible to this user: ${allSecrets.length}');
if (cleanup) {
await client.removeSecret(name, ignoreMissing: true);
print('Removed secret "$name" (--cleanup).');
}
} finally {
await client.close();
}
}
Future<String?> _resolveSecretValue({
required String? rawValue,
required String? filePath,
}) async {
if (rawValue != null) {
return rawValue;
}
if (filePath != null && filePath.isNotEmpty) {
final file = File(filePath);
if (!await file.exists()) {
stderr.writeln('Secret file not found: $filePath');
return null;
}
return file.readAsString();
}
return Platform.environment['PODMAN_EXAMPLE_SECRET'];
}
String? _readOption(List<String> args, String name) {
final prefix = '--$name=';
for (final arg in args) {
if (arg.startsWith(prefix)) {
return arg.substring(prefix.length);
}
}
return null;
}
Map<String, String> _readKeyValueOptions(List<String> args, String name) {
final prefix = '--$name=';
final output = <String, String>{};
for (final arg in args) {
if (!arg.startsWith(prefix)) {
continue;
}
final raw = arg.substring(prefix.length);
final index = raw.indexOf('=');
if (index <= 0 || index == raw.length - 1) {
continue;
}
final key = raw.substring(0, index);
final value = raw.substring(index + 1);
output[key] = value;
}
return output;
}
void _printUsage() {
print('''
Secrets workflow example
Usage:
dart run example/secrets_workflow_example.dart --name=<secret-name> [options]
Options:
--name=<name> Secret name (required)
--value=<plaintext> Secret payload value
--file=<path> Read secret payload from file
--driver=<driver> Optional driver (for example: file, pass)
--label=<k=v> Add label (repeatable)
--driver-opt=<k=v> Add driver option (repeatable)
--replace Replace existing secret with same name
--ignore Ignore creation conflict errors
--show-secret Request and display secret payload length
--cleanup Remove secret at the end of the run
--help, -h Show this help
Environment fallback:
PODMAN_EXAMPLE_SECRET Used when --value/--file are not set
''');
}