fix(security): resolve code scanning alerts
Add least-privilege 'permissions: contents: read' to quality, security and docker-ci workflows (actions/missing-workflow-permissions). Harden markdown table cell escaping in exportMarkdown: escape backslash before pipe and collapse newlines so untrusted values can't break the table (js/incomplete-sanitization). Add regression tests. ha-relevant: maybe
This commit is contained in:
@@ -6,6 +6,9 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
smoke-and-integration:
|
smoke-and-integration:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint-scripts:
|
lint-scripts:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ on:
|
|||||||
schedule:
|
schedule:
|
||||||
- cron: '0 9 * * 1' # Weekly on Monday
|
- cron: '0 9 * * 1' # Weekly on Monday
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
secrets-scan:
|
secrets-scan:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -53,6 +53,33 @@ describe('generateMarkdownTable', () => {
|
|||||||
expect(md).toContain('A\\|B')
|
expect(md).toContain('A\\|B')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('escapes backslashes before pipes so the escape char is not ambiguous', () => {
|
||||||
|
const nodes = [makeNode({ label: 'A\\|B' })]
|
||||||
|
const md = generateMarkdownTable(nodes)
|
||||||
|
// backslash doubled, then the literal pipe escaped
|
||||||
|
expect(md).toContain('A\\\\\\|B')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('collapses newlines in cell values so they do not break the table', () => {
|
||||||
|
const nodes = [makeNode({ label: 'line1\nline2', hostname: 'a\r\nb' })]
|
||||||
|
const lines = generateMarkdownTable(nodes).split('\n')
|
||||||
|
// header + separator + exactly one data row (no extra line from the value)
|
||||||
|
expect(lines).toHaveLength(3)
|
||||||
|
expect(lines[2]).toContain('line1 line2')
|
||||||
|
expect(lines[2]).toContain('a b')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('escapes pipe characters inside service names', () => {
|
||||||
|
const nodes = [makeNode({
|
||||||
|
label: 'Server',
|
||||||
|
services: [{ port: 80, protocol: 'tcp', service_name: 'web|proxy' }],
|
||||||
|
})]
|
||||||
|
const lines = generateMarkdownTable(nodes).split('\n')
|
||||||
|
// header + separator + exactly one data row — the pipe must not add a column
|
||||||
|
expect(lines).toHaveLength(3)
|
||||||
|
expect(lines[2]).toContain('web\\|proxy')
|
||||||
|
})
|
||||||
|
|
||||||
it('generates one row per non-groupRect node', () => {
|
it('generates one row per non-groupRect node', () => {
|
||||||
const nodes = [
|
const nodes = [
|
||||||
makeNode({ type: 'server', label: 'A' }, '1'),
|
makeNode({ type: 'server', label: 'A' }, '1'),
|
||||||
|
|||||||
@@ -5,8 +5,11 @@ const EMPTY = '—'
|
|||||||
|
|
||||||
function cell(v: string | null | undefined): string {
|
function cell(v: string | null | undefined): string {
|
||||||
if (!v) return EMPTY
|
if (!v) return EMPTY
|
||||||
// Escape pipe chars so they don't break the table
|
// Escape backslashes first, then pipes, and collapse newlines so they don't break the table
|
||||||
return v.replace(/\|/g, '\\|')
|
return v
|
||||||
|
.replace(/\\/g, '\\\\')
|
||||||
|
.replace(/\|/g, '\\|')
|
||||||
|
.replace(/\r?\n/g, ' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function generateMarkdownTable(nodes: Node<NodeData>[]): string {
|
export function generateMarkdownTable(nodes: Node<NodeData>[]): string {
|
||||||
@@ -27,7 +30,7 @@ export function generateMarkdownTable(nodes: Node<NodeData>[]): string {
|
|||||||
cell(d.ip),
|
cell(d.ip),
|
||||||
cell(d.hostname),
|
cell(d.hostname),
|
||||||
cell(d.status),
|
cell(d.status),
|
||||||
services,
|
cell(services),
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user