mirror of
https://github.com/morluto/rea.git
synced 2026-11-12 17:59:08 +00:00
fix(audit): report relative paths given to compiler path flags
go.build_paths only kept rooted paths, so retained build settings like CGO_CFLAGS=-Iprivate-sdk read not_observed even though the setting names a directory. Take the relative argument of a C compiler path flag, attached or in the next field. Scope this to compiler settings, because Go's own tools use the same letters for non-paths such as -B gobuildid and -T 0x1000.
This commit is contained in:
2 files changed
+75
-10
No files matched your search
@@ -1323,6 +1323,42 @@ describe("ReleaseExposureService Go Windows paths", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("ReleaseExposureService Go relative flag paths", () => {
|
||||
const goModule = (settings: { key: string; value: string }[]) => ({
|
||||
path: "github.com/acme/app",
|
||||
main: null,
|
||||
dependencies: [],
|
||||
settings,
|
||||
unparsed_lines: [],
|
||||
unparsed_line_bytes_base64: [],
|
||||
complete: true,
|
||||
});
|
||||
|
||||
it("keeps relative paths given to compiler path flags, attached or not", async () => {
|
||||
const report = await goReport(
|
||||
goModule([
|
||||
{ key: "CGO_CFLAGS", value: "-Iprivate-sdk -O2 -isystem vendor/sdk" },
|
||||
{ key: "CGO_LDFLAGS", value: "-Llibs -lssl" },
|
||||
]),
|
||||
);
|
||||
const check = report.checks.find((item) => item.id === "go.build_paths");
|
||||
expect(check?.status).toBe("exposed");
|
||||
expect(check?.observation.samples).toEqual([
|
||||
"private-sdk",
|
||||
"vendor/sdk",
|
||||
"libs",
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not read Go linker arguments as relative paths", async () => {
|
||||
const report = await goReport(
|
||||
goModule([{ key: "-ldflags", value: "-B gobuildid -T 0x1000 -s -w" }]),
|
||||
);
|
||||
const check = report.checks.find((item) => item.id === "go.build_paths");
|
||||
expect(check?.status).toBe("not_observed");
|
||||
});
|
||||
});
|
||||
|
||||
describe("ReleaseExposureService Go paths", () => {
|
||||
it("keeps Go paths with spaces and attached compiler flags whole", async () => {
|
||||
const report = await goReport({
|
||||
|
||||
@@ -784,19 +784,46 @@ const GO_FLAG_FIELD = /(?:[^\s"']|"[^"]*"|'[^']*')+/gu;
|
||||
const GO_FLAG_PATH =
|
||||
/(?:^|[\s=,])(?:-(?:idirafter|imacros|include|iprefix|iquote|isysroot|isystem|[BFILT]))?((?:\.{1,2}[\\/]|\/|[A-Za-z]:[\\/]|\\{2}[^\\\s=,]+\\)[^=,]+)/gu;
|
||||
|
||||
/** Paths in one flag value, with a quoted path kept whole up to the next flag. */
|
||||
const goFlagPaths = (value: string): string[] =>
|
||||
/**
|
||||
* Settings read by a C compiler, where the flags below take a directory or file.
|
||||
* Go's own tools reuse those letters: `-ldflags` takes `-B gobuildid` and
|
||||
* `-T 0x1000`, so their relative arguments are not paths.
|
||||
*/
|
||||
const GO_COMPILER_SETTING = /^(?:CGO_[A-Z]+FLAGS|-gccgoflags)$/u;
|
||||
const GO_COMPILER_PATH_FLAG =
|
||||
/^-(?:idirafter|imacros|include|iprefix|iquote|isysroot|isystem|[BFILT])=?(.*)$/su;
|
||||
|
||||
/** Flags in one value, with a quoted path kept whole up to the next flag. */
|
||||
const goFlags = (value: string): string[] =>
|
||||
[...value.matchAll(GO_FLAG_FIELD)].flatMap(([field]) =>
|
||||
field
|
||||
.replace(/["']/gu, "")
|
||||
.split(/\s+(?=-)/u)
|
||||
.flatMap((flag) =>
|
||||
[...flag.matchAll(GO_FLAG_PATH)].flatMap(([, path]) =>
|
||||
path === undefined ? [] : [path.trimEnd()],
|
||||
),
|
||||
),
|
||||
field.replace(/["']/gu, "").split(/\s+(?=-)/u),
|
||||
);
|
||||
|
||||
const goFlagPaths = (value: string): string[] =>
|
||||
goFlags(value).flatMap((flag) =>
|
||||
[...flag.matchAll(GO_FLAG_PATH)].flatMap(([, path]) =>
|
||||
path === undefined ? [] : [path.trimEnd()],
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* A path flag's relative argument, attached or in the next field. A rooted
|
||||
* argument belongs to `goFlagPaths`, which keeps its `=` and `,` structure.
|
||||
*/
|
||||
const goCompilerFlagPaths = (value: string): string[] =>
|
||||
goFlags(value).flatMap((flag, index, flags) => {
|
||||
const attached = GO_COMPILER_PATH_FLAG.exec(flag)?.[1]?.trimEnd();
|
||||
if (attached === undefined) return [];
|
||||
const next = flags[index + 1];
|
||||
const argument =
|
||||
attached.length > 0 || next?.startsWith("-") === true ? attached : next;
|
||||
return argument === undefined ||
|
||||
argument.length === 0 ||
|
||||
filesystemPath(argument) !== null
|
||||
? []
|
||||
: [argument];
|
||||
});
|
||||
|
||||
const goPaths = (
|
||||
module: NonNullable<GoBinary["build_info"]>["module"],
|
||||
): string[] => {
|
||||
@@ -815,6 +842,8 @@ const goPaths = (
|
||||
for (const setting of module.settings) {
|
||||
if (!GO_FLAG_SETTING.test(setting.key)) continue;
|
||||
for (const path of goFlagPaths(setting.value)) add(path);
|
||||
if (GO_COMPILER_SETTING.test(setting.key))
|
||||
for (const path of goCompilerFlagPaths(setting.value)) paths.add(path);
|
||||
}
|
||||
return [...paths];
|
||||
};
|
||||
Reference in new issue
Block a user