fix(packaging): reject advanced Snap YAML semantics

This commit is contained in:
4gray committed 2026-07-17 22:42:37 +02:00
1 parent 406a20851b
commit 809182ca06
2 files changed
+116

No files matched your search

@@ -464,6 +464,76 @@ function yamlSequenceIncludes(lines, entry, expected) {
);
}
function yamlSyntaxOutsideQuotedScalars(line) {
let result = '';
let quote = null;
for (let index = 0; index < line.length; index += 1) {
const character = line[index];
if (quote === "'") {
if (character === "'" && line[index + 1] === "'") {
result += ' ';
index += 1;
} else {
result += ' ';
if (character === "'") {
quote = null;
}
}
continue;
}
if (quote === '"') {
result += ' ';
if (character === '\\') {
result += ' ';
index += 1;
} else if (character === '"') {
quote = null;
}
continue;
}
if (character === '#') {
break;
}
if (character === "'" || character === '"') {
quote = character;
result += ' ';
continue;
}
result += character;
}
return result;
}
function containsUnsupportedYamlSemantics(lines) {
let blockScalarParentIndent = null;
for (const line of lines) {
if (!line.trim()) {
continue;
}
const lineIndent = line.length - line.trimStart().length;
if (
blockScalarParentIndent !== null &&
lineIndent > blockScalarParentIndent
) {
continue;
}
blockScalarParentIndent = null;
const syntax = yamlSyntaxOutsideQuotedScalars(line);
if (
/(?:^|[\s:[\]{},])(?:[&*][A-Za-z0-9_-]+|![^\s,[\]{}]+)(?=$|[\s,\]}])/.test(
syntax
) ||
/(?:^|\s)<<\s*:/.test(syntax)
) {
return true;
}
if (/:\s*[>|][+-]?\d?\s*$/.test(syntax)) {
blockScalarParentIndent = lineIndent;
}
}
return false;
}
export function validateExtractedSnapMetadata(extractionRoot) {
const snapYamlPath = path.join(extractionRoot, 'meta', 'snap.yaml');
let stat;
@@ -492,6 +562,11 @@ export function validateExtractedSnapMetadata(extractionRoot) {
];
}
const lines = contents.split(/\r?\n/);
if (containsUnsupportedYamlSemantics(lines)) {
return [
'Extracted Snap metadata must not use YAML anchors, aliases, merge keys, or custom tags.',
];
}
const errors = [];
const plugs = singleYamlMappingEntry(
lines,
@@ -575,6 +575,8 @@ test('requires a private top-level shared-memory plug used by the Snap app', ()
const validSnapYaml = [
'name: iptvnator',
'summary: "*literal &anchor !tag <<: is quoted"',
'# *commented-alias &commented-anchor !commented-tag',
'apps:',
' iptvnator:',
' command: iptvnator',
@@ -660,6 +662,45 @@ test('requires a private top-level shared-memory plug used by the Snap app', ()
),
/plug keys.*unique/i,
],
[
(contents) =>
[
'shared-interface: &sharedInterface shared-memory',
contents.replace(
'\nplugs:\n',
'\nplugs:\n alias-plug:\n interface: *sharedInterface\n'
),
].join('\n'),
/anchors, aliases, merge keys, or custom tags/i,
],
[
(contents) =>
[
'shared-interface: &sharedInterface shared-memory',
`${contents}slots:\n alias-slot:\n interface: *sharedInterface\n`,
].join('\n'),
/anchors, aliases, merge keys, or custom tags/i,
],
[
(contents) =>
contents.replace(
'\nplugs:\n',
'\nplugs:\n tagged:\n interface: !shared-memory shared-memory\n'
),
/anchors, aliases, merge keys, or custom tags/i,
],
[
(contents) =>
[
'shared-plug: &sharedPlug',
' interface: network',
contents.replace(
'\nplugs:\n',
'\nplugs:\n merged:\n <<: *sharedPlug\n'
),
].join('\n'),
/anchors, aliases, merge keys, or custom tags/i,
],
[
(contents) =>
contents.replace(