buildSecretVars function

Future<Map<String, String>> buildSecretVars({
  1. required String token,
  2. required String buildJobId,
  3. required String runId,
  4. required BuildJob buildJob,
  5. required ApiClient apiClient,
})

Implementation

Future<Map<String, String>> buildSecretVars({
  required String token,
  required String buildJobId,
  required String runId,
  required BuildJob buildJob,
  required ApiClient apiClient,
}) async {
  final secrets = <String, String>{'GITHUB_TOKEN': token};

  final teamId = buildJob.teamId;
  if (teamId == null) return secrets;

  final secretMetadataList = await apiClient.getSecrets(teamId);
  if (secretMetadataList.isEmpty) return secrets;

  final workflowFileName = buildJob.workflowFileName;
  if (workflowFileName == null || workflowFileName.isEmpty) {
    throw ArgumentError('workflowFileName is required to resolve secrets.');
  }

  Set<String>? usedSecretNames;
  try {
    await logInfo(
      buildJobId,
      runId,
      'Fetching workflow $workflowFileName from GitHub to analyze referenced secrets...',
    );
    final workflowContent = await fetchWorkflowContent(
      owner: buildJob.owner,
      repo: buildJob.repo,
      workflowFileName: workflowFileName,
      token: token,
      githubApiBaseUrl: buildJob.githubBaseUrl,
      commitSha: buildJob.commitSha,
      branch: buildJob.branch,
    );
    usedSecretNames = extractSecretNames(workflowContent);
    await logInfo(
      buildJobId,
      runId,
      'Referenced secret(s) in workflow: ${usedSecretNames.isEmpty ? "(none)" : usedSecretNames.join(', ')}',
    );
  } catch (e) {
    await logWarning(
      buildJobId,
      runId,
      'Failed to fetch or analyze workflow file; falling back to loading all secrets: $e',
    );
  }

  // Filter list by referenced secret names (or load all if analysis failed)
  final targetSecrets = secretMetadataList.where((meta) {
    if (usedSecretNames == null) return true;
    final name = meta['name'] as String?;
    return name != null && usedSecretNames.contains(name);
  }).toList();

  if (targetSecrets.isEmpty) {
    await logInfo(buildJobId, runId, 'No secrets need to be loaded');
    return secrets;
  }

  await logInfo(
    buildJobId,
    runId,
    'Loading ${targetSecrets.length} secret(s) from OpenCI Server...',
  );

  for (final meta in targetSecrets) {
    final name = meta['name'] as String?;
    if (name == null) continue;

    try {
      final value = await apiClient.getSecretValue(teamId, name);
      if (value.isNotEmpty) {
        secrets[name] = value;
      }
    } catch (e) {
      await logWarning(buildJobId, runId, 'Failed to load secret "$name": $e');
    }
  }

  await logInfo(buildJobId, runId, 'Loaded ${targetSecrets.length} secret(s)');

  return secrets;
}