Skip to content

Add "View Autofixes" feature for variant analysis results #4065

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 31 commits into
base: main
Choose a base branch
from

Conversation

jcogs33
Copy link

@jcogs33 jcogs33 commented Jun 29, 2025

Description

Adds a "View Autofixes" feature for variant analysis results. This is a canary-only feature.
Generates autofixes for selected variant analysis results and opens the resulting autofix outputs in a markdown file.
Activated via the "View Autofixes" button in the variant analysis webview or via right-clicking the variant analysis query history item.

AutofixInMrvaScreenshot

At a high-level, the implementation:
  • Checks for a local checkout of autofix
  • Sets up to run autofix by:
    • Overriding the relevant query help
    • Getting the relevant SARIF(s)
    • Downloading source root(s)
  • Runs autofix locally
  • Outputs autofix results in a markdown file

Commit-by-commit review recommended. Let me know if you want me to split anything onto a separate PR.

Consideration

  • See in-line comments
  • Change from my original implementation: Instead of downloading databases and then extracting the source root from the database, I directly download the source root since it seemed a bit faster. Let me know if you think the database approach is better.
  • I will make a follow-up PR to convert this to support Go autofix instead of cocofix, and I'll update the queryHelpOverrideDirectory to the new go/pkg/autofix/prompt/qhelps directory in that PR.

Testing

  • I've manually tested this feature but have not added unit/view/integration tests since it seems another canary feature did not add tests. Let me know if I should add tests after all.
  • Note: There is a known issue with the E2E CI test failing. It is not caused by changes in this PR.

@jcogs33 jcogs33 force-pushed the jcogs33/view-autofixes branch 3 times, most recently from 8095989 to c5f0e5e Compare June 30, 2025 21:29
@jcogs33 jcogs33 force-pushed the jcogs33/view-autofixes branch from c5f0e5e to 3ff5d64 Compare July 2, 2025 00:44
filterSort: RepositoriesFilterSortStateWithIds = defaultFilterSortState,
variantAnalyses: Map<number, VariantAnalysis>,
credentials: Credentials,
logger: NotificationLogger,
Copy link
Author

Choose a reason for hiding this comment

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

In retrospect, I'm not sure if I should be using NotificationLogger. 🤔 Let me know if I should use extLogger instead of or in addition to NotificationLogger?
Also let me know if I should add more logging in general?

Copy link
Member

Choose a reason for hiding this comment

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

If you aren't showing notifications, I think you can use the BaseLogger type here.

* @throws Error if the AUTOFIX_PATH environment variable is not set or the path does not exist.
*/
function findLocalAutofix(): string {
const localAutofixPath = process.env.AUTOFIX_PATH;
Copy link
Author

Choose a reason for hiding this comment

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

I'm currently requiring that users set this environment variable (see corresponding documentation). Let me know if there is something better I should do (config file, etc.) instead of using this environment variable.

Copy link
Member

Choose a reason for hiding this comment

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

I think using a config setting would make sense (something like codeQL.autofix.path). I'm not sure how VS Code picks up environment variables, but it's a lot easier to set config settings than environment variables.

@jcogs33 jcogs33 marked this pull request as ready for review July 2, 2025 02:21
@jcogs33 jcogs33 requested review from a team as code owners July 2, 2025 02:21
Copy link
Member

@koesie10 koesie10 left a comment

Choose a reason for hiding this comment

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

Thanks! I've not tested this locally, but the demo you shared looks good!

filterSort: RepositoriesFilterSortStateWithIds = defaultFilterSortState,
variantAnalyses: Map<number, VariantAnalysis>,
credentials: Credentials,
logger: NotificationLogger,
Copy link
Member

Choose a reason for hiding this comment

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

If you aren't showing notifications, I think you can use the BaseLogger type here.

"--source-root",
srcRootPath,
"--model",
"capi-dev-4o", // may fail with older versions of cocofix
Copy link
Member

Choose a reason for hiding this comment

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

Should this be configurable (something like codeQL.autofix.model)?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes. gpt 4o is going away soon. And we are trying various models to replace it.

Comment on lines +650 to +653
env: {
CAPI_DEV_KEY: process.env.CAPI_DEV_KEY,
PATH: process.env.PATH,
},
Copy link
Member

Choose a reason for hiding this comment

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

Would it make sense to allow specifying the environment variables in the config (in something like codeQL.autofix.env)?

if (showCommand) {
void logger.log(`Spawning '${bin} ${args.join(" ")}' in ${cwd}`);
}
if (args.some((a) => a === undefined || a === "")) {
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we need this check, it's fine for the command to fail if this is the case.

`Invalid empty or undefined arguments: ${args.join(" ")}`,
);
}
const p = spawn(bin, args, { stdio: [0, 1, 2], ...options });
Copy link
Member

Choose a reason for hiding this comment

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

I think stdio: [0, 1, 2] will ensure that the autofix CLI logs to the stdout/stderr of VS Code, but I don't think you can view those. I think it would make sense to log those to the extension logs. A good example of this can be found in runCodeQlCliInNewProcess, specifically in handleProcessOutput.

Copy link
Contributor

@aeisenberg aeisenberg left a comment

Choose a reason for hiding this comment

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

Looks good. I haven't tried this locally.

Comment on lines +188 to +189
localAutofixPath,
"prompt-templates",
Copy link
Contributor

Choose a reason for hiding this comment

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

Does localAutofixPath need to be a checkout of the autofix repo? Or does it point to a binary?

The new location for the qhelp overrides is here: go/pkg/autofix/prompt/qhelps. But, this is only available in a full checkout of the repo. It's not available with the go binary. The cocofix prompt-templates will go away.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, it needs to be a checkout of the autofix repo. Will that be a problem for any reason?
I've included instructions about checking out the repo in the documentation for this feature (see documentation links beneath my original commits). Note that DCA also expects a checkout of the autofix repo when running autofix locally with DCA, and I mimicked that expectation.

I'll update the prompt-template directory when I do a follow-up PR to update from cocofix to Go.


// Extract the tarball
await new Promise<void>((resolve, reject) => {
const process = spawn("tar", ["-xzf", tarballPath], { cwd: downloadDir });
Copy link
Contributor

Choose a reason for hiding this comment

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

We're using tar-stream elsewhere for extracting tarballs. It would be better to use something like that instead of spawning a new process.

Just be aware that tar-stream is currently a dev dependency and would need to be moved to a dependency.

} = await getRepoStoragePaths(autofixOutputStoragePath, nwo);

// Get autofix binary.
// Switch to Go binary in the future and have user pass full path
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes.

"--source-root",
srcRootPath,
"--model",
"capi-dev-4o", // may fail with older versions of cocofix
Copy link
Contributor

Choose a reason for hiding this comment

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

Yes. gpt 4o is going away soon. And we are trying various models to replace it.

"```\n\n</details>\n\n ### Notes\n - notes placeholder\n\n";

// Format the content with Markdown
const formattedContent = `## ${header}\n\n${frontFormatting}${content}${backFormatting}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

If content itself has three backticks, then this formatting will be broken. I don't know how likely that is. In this case, probably just doing a find/replace of three with \``.

@jcogs33
Copy link
Author

jcogs33 commented Jul 3, 2025

Thanks for the reviews @koesie10 and @aeisenberg! 🙇
I've addressed some of your comments. I'll re-request your reviews once I'm finished with them all.

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.

3 participants