(ctx context.Context, attestationID, materialName, materialValue, materialType string, annotations map[string]string, policyInputFiles []*PolicyInputFromFile)
| 82 | var ErrAttestationNotInitialized = errors.New("attestation not yet initialized") |
| 83 | |
| 84 | func (action *AttestationAdd) Run(ctx context.Context, attestationID, materialName, materialValue, materialType string, annotations map[string]string, policyInputFiles []*PolicyInputFromFile) (*AttestationStatusMaterial, error) { |
| 85 | // initialize the crafter. If attestation-id is provided we assume the attestation is performed using remote state |
| 86 | crafter, err := newCrafter(&newCrafterStateOpts{enableRemoteState: (attestationID != ""), localStatePath: action.localStatePath}, action.CPConnection, action.opts...) |
| 87 | if err != nil { |
| 88 | return nil, fmt.Errorf("failed to load crafter: %w", err) |
| 89 | } |
| 90 | |
| 91 | // Resolve runtime policy inputs from the provided files before adding the |
| 92 | // material, so a malformed file aborts the add early. |
| 93 | runtimeInputs, err := buildRuntimeInputs(policyInputFiles) |
| 94 | if err != nil { |
| 95 | return nil, err |
| 96 | } |
| 97 | |
| 98 | if initialized, err := crafter.AlreadyInitialized(ctx, attestationID); err != nil { |
| 99 | return nil, fmt.Errorf("checking if attestation is already initialized: %w", err) |
| 100 | } else if !initialized { |
| 101 | return nil, ErrAttestationNotInitialized |
| 102 | } |
| 103 | |
| 104 | if err := crafter.LoadCraftingState(ctx, attestationID); err != nil { |
| 105 | action.Logger.Err(err).Msg("loading existing attestation") |
| 106 | return nil, err |
| 107 | } |
| 108 | |
| 109 | // Default to inline CASBackend and override if we are not in dry-run mode |
| 110 | casBackend := &casclient.CASBackend{ |
| 111 | Name: "not-set", |
| 112 | } |
| 113 | |
| 114 | // Define CASbackend information based on the API response |
| 115 | if !crafter.CraftingState.GetDryRun() { |
| 116 | client := pb.NewAttestationServiceClient(action.CPConnection) |
| 117 | workflowRunID := crafter.CraftingState.GetAttestation().GetWorkflow().GetWorkflowRunId() |
| 118 | _, connectionCloserFn, getCASBackendErr := getCASBackend(ctx, client, workflowRunID, action.casCAPath, action.casURI, action.connectionInsecure, action.Logger, casBackend, action.CLIVersion) |
| 119 | if getCASBackendErr != nil { |
| 120 | return nil, fmt.Errorf("failed to get CAS backend: %w", getCASBackendErr) |
| 121 | } |
| 122 | if connectionCloserFn != nil { |
| 123 | // nolint: errcheck |
| 124 | defer connectionCloserFn() |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | // Add material to the attestation crafting state based on if the material is contract free or not. |
| 129 | // The checks are performed in the following order: |
| 130 | // 1. If materialName is empty and materialType is empty, we don't know anything about the material so, we add it with auto-detected kind and random name |
| 131 | // 2. If materialName is not empty, check if the material is in the contract. If it is, add material from contract |
| 132 | // 2.1. If materialType is empty, try to guess the material kind with auto-detected kind and materialName |
| 133 | // 3. If materialType is not empty, add material contract free with materialType and materialName |
| 134 | addOpts := runtimeInputAddOpts(runtimeInputs) |
| 135 | |
| 136 | var mt *api.Attestation_Material |
| 137 | switch { |
| 138 | case materialName == "" && materialType == "": |
| 139 | mt, err = crafter.AddMaterialContactFreeWithAutoDetectedKind(ctx, attestationID, "", materialValue, casBackend, annotations, addOpts...) |
| 140 | if err != nil { |
| 141 | return nil, fmt.Errorf("adding material: %w", err) |
no test coverage detected