Skip to content

feat: Aviator apply-remediations issue-id filtering for SSC/FoD#1050

Open
kireetivar wants to merge 8 commits into
fortify:feat/v3.x/aviator/26.4from
kireetivar:p/kireetivar/filter_by_id
Open

feat: Aviator apply-remediations issue-id filtering for SSC/FoD#1050
kireetivar wants to merge 8 commits into
fortify:feat/v3.x/aviator/26.4from
kireetivar:p/kireetivar/filter_by_id

Conversation

@kireetivar

@kireetivar kireetivar commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Note: This PR will be merged into feat/v3.x/aviator/26.4

This PR adds remediations cache download/apply workflows for SSC and FoD so teams can download remediations once into a cache zip and apply them locally, including optional issue-level filtering.

What changed

  • Added new cache download commands:
    • fcli aviator ssc download-remediations-cache
    • fcli fod aviator download-remediations-cache
  • Extended existing apply commands:
    • fcli aviator ssc apply-remediations
    • fcli fod aviator apply-remediations
  • Added --from-cache support to SSC and FoD apply-remediations.
  • Added --issue-ids support for cache-based apply-remediations.
  • Added shared cache zip handling for manifest, entry ordering, checksum validation, reading, and writing.
  • Added SSC support for cache generation from:
    • --artifact-id
    • --latest
    • --all
  • Added FoD support for cache generation from:
    • --release / --rel
  • Added resilient handling for cache entries that do not contain remediations.xml.

Behavior

  • With --from-cache:
    • Apply-remediations reads FPRs from the cache zip in manifest order.
    • SSC and FoD process cached entries sequentially.
  • With --issue-ids:
    • Only remediations whose instanceId matches requested ids are considered.
    • --issue-ids is only supported together with --from-cache.
  • Without --issue-ids:
    • Existing apply-remediations behavior is unchanged for non-cache flows.
  • If a cached FPR does not contain remediations.xml:
    • The entry is skipped instead of failing the entire cache-based run.

SSC cache behavior

  • download-remediations-cache --all stores artifacts in chronological order.
  • apply-remediations --from-cache processes entries in the same stored order.
  • Output reports:
    • processed entries
    • skipped entries
    • processed artifact ids

FoD cache behavior

  • download-remediations-cache stores the selected release FPR in the cache zip.
  • apply-remediations --from-cache processes entries in cache order.
  • Output reports:
    • processed entries
    • processed release ids`

apply-remediations command additions

  • fcli aviator ssc apply-remediations --from-cache <zip>
  • fcli aviator ssc apply-remediations --from-cache <zip> --issue-ids <id1,id2,...>
  • fcli fod aviator apply-remediations --from-cache <zip>
  • fcli fod aviator apply-remediations --from-cache <zip> --issue-ids <id1,id2,...>

@kireetivar
kireetivar requested a review from rsenden July 6, 2026 08:58
@kireetivar kireetivar self-assigned this Jul 6, 2026

@rsenden rsenden left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done a partial review and added some individual code comments, which mostly originate from current (command) design. Can we improve the design, thereby automatically resolving most of these comments?

I think the key issue is that these commands operate on individual FPR files, thus requiring separate --file/--dir output options depending on how many FPRs are being downloaded, and deviating from fcli arity conventions to pass these FPRs through wildcards to apply-remediations commands. Also, when depending on user-specified dirs/wildcards, there's a risk that incorrect FPR files get picked up, for example from a previous run, possibly even from a different app version/release.

Three alternative approaches come to mind (but maybe you can think of other approaches):

  1. Get rid of download-remediations-fpr commands, and instead add caching options on apply-remediations commands, for example a --[no-]use-cache option that checks fcli state directory whether cached FPR files for current set of args (--av/--rel & artifact selection criteria) is available, downloading these to the cache on the fly if not yet available or outdated. Main complexity is cache management, for example requiring extra commands/options for updating or clearing cache, detecting outdated cache, ...
  2. Have download-remediations-fpr (possibly renamed to something like prepare-remediations-cache output a single 'remediations cache' zip file; depending on FPR selection criteria, this zip-file can contain either single or multiple FPR files, which users can then pass to apply-remediations cmd using --from-cache=<zip-file>
  3. Combination of the above; have apply-remediations --use-cache=<zip-file>; if given zip-file exists, it's used as is, otherwise it's created by downloading FPR files based on current FPR selection criteria. Possibly, the zip-file could contain metadata like app version/release and FPR selection criteria; if there's a mismatch with current selection criteria on the apply-remediations command, an error would be thrown.


@Override
public boolean isSingular() {
return true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the rationale for having singular output with artifact id's embedded in that single output record, rather than outputting separate records for every individual artifact? Unless there are good reasons against the latter, that's the more common fcli convention.

result.putArray("artifactIds").add(artifact.getId());
result.putArray("files").add(destination.toString());
result.put("file", destination.toString());
result.put(IActionCommandResultSupplier.actionFieldName, getActionCommandResult());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fcli output framework automatically sets the 'action' column based on getActionCommandResult; explicitly setting this field is only necessary if you want to display dynamic action values, i.e., if that value depends on execution flow/result.

files.add(destination.toString());
artifactIds.add(artifact.getId());
}
result.put(IActionCommandResultSupplier.actionFieldName, getActionCommandResult());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fcli output framework automatically sets the 'action' column based on getActionCommandResult; explicitly setting this field is only necessary if you want to display dynamic action values, i.e., if that value depends on execution flow/result.

throw new FcliSimpleException("--dir must be specified when using --all");
}
} else if (outputDir != null) {
throw new FcliSimpleException("--dir can only be used with --all; use -f/--file for a single FPR download");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is --dir not supported for single-file downloads, using the default FPR file name as defined in getSingleDestination.

private boolean latest;

@Option(names = {"--all"}, required = true, descriptionKey = "fcli.aviator.ssc.download-remediations-fpr.all")
private boolean allOpenIssues;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird field name for 'all FPRs'


@Option(names = {"--fpr"}, required = true, arity = "1..*", paramLabel = "<file>",
descriptionKey = "fcli.aviator.ssc.apply-remediations.fpr")
@DisableTest({TestType.MULTI_OPT_SPLIT, TestType.MULTI_OPT_PLURAL_NAME, TestType.OPT_ARITY_VARIABLE})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the rationale for non-standard arity and the disabled tests is to allow this to work with wildcard patterns, i.e., --fpr /path/to/downloads/*.fpr? Although picocli does its best to handle multi-arity options, we encountered issues with this in the past, hence we usually disallow this.

return outputFile == null ? Path.of(String.format("remediations_artifact_%s.fpr", artifact.getId())) : outputFile.toPath();
}

private void validateDestinationOptions() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I don't like exclusive sets of options as it affects user experience (difficult to figure out which sets of options can be combined), nor manual validation instead of picocli handling option exclusivity (also to properly display this in command syntax). Any way around this, by reorganizing ArgGroups?

@kireetivar

Copy link
Copy Markdown
Contributor Author

Thanks for the review comments. I’m planning to revise the PR away from the current raw-FPR workflow.

Proposed solution:

  • I am more inclined toward your option 2, with one explicit cache/archive file produced by the download command and consumed by apply.
  • Replace download-remediations-fpr with download-remediations-cache.
  • Remove the multi-arity --fpr option completely.
  • Use a single cache zip with manifest.json and ordered FPR entries.

Example manifest.json:

{
  "schemaVersion": 1,
  "kind": "aviator-remediations-cache",
  "product": "ssc",
  "createdAt": "2026-07-16T12:00:00Z",
  "selection": {
    "mode": "all",
    "appVersionId": "10001",
    "since": "2026-07-01T00:00:00Z"
  },
  "entries": [
    {
      "order": 1,
      "artifactId": "12345",
      "uploadDate": "2026-07-10T08:00:00Z",
      "path": "fprs/001_artifact_12345.fpr",
      "sha256": "8f14e45fceea167a5a36dedd4bea2543"
    },
    {
      "order": 2,
      "artifactId": "67890",
      "uploadDate": "2026-07-11T09:30:00Z",
      "path": "fprs/002_artifact_67890.fpr",
      "sha256": "45c48cce2e2d7fbdea1afc51c7c6ad26"
    }
  ]
}
  • Use --from-cache <zip> on apply-remediations, but not as a standalone source. The normal selection options are still required:
    • SSC: --artifact-id, or --latest/--all --av ...
    • FoD: --rel
  • If the cache exists, apply validates the manifest against the current selection. If it does not exist, the user should create it first with download-remediations-cache.
  • --issue-ids will require --from-cache, so filtered/partial applies do not repeatedly download from FoD/SSC.
  • The manifest will include product, server, selection metadata, ordered entries, upload dates, and required sha256; apply will verify checksums before modifying source.
  • Use the same --from-cache option name for SSC and FoD.

If you are ok with this proposal, I have a few questions I’d like your input on:

  1. Are the proposed option/command names OK: download-remediations-cache and --from-cache?
  2. Should --file be required for download-remediations-cache, or should we provide a deterministic default cache filename?
  3. Should download-remediations-cache overwrite existing files by default, fail by default, or require an explicit --overwrite option?
  4. If the selected SSC/FoD criteria resolve to zero matching artifacts, should we create an empty valid cache, or should cache download fail?

@rsenden

rsenden commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

I don't have a strong preference for either option 2 or 3:

  • Option 2 provides a more explicit split between creating the cache, and consuming the cache, but requires an extra command to be run
  • Option 3 allows for simply running the same command (with different issue id's) multiple times, automatically creating and consuming the cache as needed, but it may be slightly confusing that the --use-cache is used for both initial creation of the cache, and consuming it in subsequent runs

For option 2, I think it's better to have --from-cache being mutually exclusive with --av/--rel and artifact selection options; i.e., users either apply remediations from cache, or from the existing artifact selection options. This is more user-friendly (no need to repeat same options on download-remediations-cache and apply-remediations), and saves us from having to validate that apply-remediations options match the cache.

For option 3, we would need to verify options against cache, but then need to decide what to do if there's a mismatch; throw an error, replace the cache based on current selection options, ...

  1. Are the proposed option/command names OK: download-remediations-cache and --from-cache?

Yes, if we go for option 2

  1. Should --file be required for download-remediations-cache, or should we provide a deterministic default cache filename?

I think requiring --file is better, providing a clear link between download-remediations-cache and apply-remediations

  1. Should download-remediations-cache overwrite existing files by default, fail by default, or require an explicit --overwrite option?

Use CommonOptionMixins::RequireConfirmation mixin (see existing usages in fcli as example)

  1. If the selected SSC/FoD criteria resolve to zero matching artifacts, should we create an empty valid cache, or should cache download fail?

Not sure; probably should have same behavior as current non-cache based apply-remediations. Output should probably show the number of downloaded artifacts.

@kireetivar
kireetivar requested a review from rsenden July 17, 2026 11:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants