Skip to content
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

Source clouds table and scope table from compliance monitor #262

Merged
merged 3 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids",
"typecheck": "tsc",
"postinstall": "node getDocs.js && node populateStds.js && node populateCerts.js",
"postinstall": "node getDocs.js && node populateStds.js && node populateCerts.js && node populateClouds.js",
"test": "echo \"Error: no test specified\" && exit 1",
"lint:md": "markdownlint-cli2 \"**/*.md\"",
"fix:md": "markdownlint-cli2-fix \"**/*.md\"",
Expand All @@ -54,6 +54,7 @@
"lint-staged": "^13.1.2",
"markdownlint-cli2": "^0.7.1",
"markdownlint-rule-search-replace": "^1.0.9",
"node-fetch": "^2.7.0",
"prettier": "^2.8.4",
"prism-react-renderer": "^2.3.1",
"react": "^18.2.0",
Expand Down
118 changes: 28 additions & 90 deletions populateCerts.js
Original file line number Diff line number Diff line change
@@ -1,108 +1,46 @@
const fetch = require('node-fetch')
const fs = require('fs')
const YAML = require('yaml')

async function fetchScopeTable(uuid, title, path) {
const response = await fetch(
`https://compliance.sovereignit.cloud/markdown/scope/${uuid}`
)
var text = await response.text()
text = `# ${title}\n\n${text}`
fs.writeFileSync(path, text, 'utf8')
}

// how many outdated versions of any scope to include
const MAX_OLD = 1

const filenames = fs
.readdirSync('standards/')
.filter((fn) => fn.startsWith('scs-') && fn.endsWith('.yaml'))
.readdirSync('standards/')
.filter((fn) => fn.startsWith('scs-') && fn.endsWith('.yaml'))

const scopes = filenames.map((filename) => {
return {
...YAML.parseDocument(fs.readFileSync(`standards/${filename}`, 'utf8')).toJSON(),
filename,
id: filename.substring(0, filename.length - 5),
}
return {
...YAML.parseDocument(
fs.readFileSync(`standards/${filename}`, 'utf8')
).toJSON(),
filename,
id: filename.substring(0, filename.length - 5)
}
})

const today = new Date().toISOString().slice(0, 10)

const sidebarItems = scopes.map((scope) => {
const matrix = {}
const versionsShown = {}
var numOld = 0
var modules = {}
scope.modules.forEach((module) => {
modules[module.id] = module
module.prettyName = module.id.startsWith('scs-') ? `${module.id}: ${module.name}` : module.name
})
scope.timeline.sort((a, b) => b.date.localeCompare(a.date))
const current = scope.timeline.filter((entry) => entry.date <= today)
const lookup = current.length ? current[0].versions : {}
// sort in descending order, so we get the MAX_OLD most recent obsolete versions
scope.versions.sort((a, b) => b.version.localeCompare(a.version));
scope.versions.forEach((version) => {
version.state = lookup[version.version] || 'deprecated'
version.isStable = version.stabilized_at !== undefined && version.stabilized_at <= today
version.isEffective = version.state == 'effective'
if (['warn', 'effective', 'draft'].indexOf(version.state) == -1) {
numOld += 1
if (numOld > MAX_OLD) return
}
if (version.include === undefined) return
versionsShown[version.version] = version
version.include.forEach((include) => {
if (include.ref === undefined) {
include = {ref: include, parameters: {}}
}
const module = modules[include.ref]
if (matrix[module.id] === undefined) {
matrix[module.id] = {
name: module.prettyName,
columns: {},
url: module.url,
}
}
matrix[module.id].columns[version.version] = {
parameters: include.parameters,
}
})
})

const rows = Object.values(matrix)
const columns = Object.keys(versionsShown)
rows.sort((a, b) => a.name.localeCompare(b.name));
columns.sort((a, b) => a.localeCompare(b));

lines = [`# ${scope.name}

Note that the state _Stable_ is shown here if _stabilized at_ is in the future, whereas _Effective_ is shown here if _stabilized at_ is in the past and _deprecated at_ is unset or in the future.
`]
lines.push('| Scope versions -> | ' + columns.join(' | ') + ' |')
lines.push('| :-- | ' + columns.map(() => ':--').join(' | ') + ' |')
lines.push('| State | ' + columns.map((c) => versionsShown[c].state).join(' | ') + ' |')
lines.push('| Stabilized at | ' + columns.map((c) => versionsShown[c].stabilized_at || '').join(' | ') + ' |')
// lines.push('| Deprecated at | ' + columns.map((c) => versionsShown[c].deprecated_at || '').join(' | ') + ' |')
// md doesn't allow intermediate header rows
// lines.push('| :-- | ' + columns.map(() => ':--').join(' | ') + ' |')
lines.push('| **Modules** | ' + columns.map((c) => ' '.repeat(c.length)).join(' | ') + ' |')
// md doesn't allow intermediate header rows
// lines.push('| :-- | ' + columns.map(() => ':--').join(' | ') + ' |')
rows.forEach((row) => {
lines.push(`| [${row.name}](${row.url}) | ` + columns.map((c) => row.columns[c]).map((col) => {
if (col === undefined) {
// this version of the cert does not include this standard
return ''
}
let params = Object.entries(col.parameters || {}).map((entry) =>
entry[1].startsWith('https://') ? `[${entry[0]}](${entry[1]})` : `${entry[0]}=${entry[1]}`
).join(', ')
if (params.length) {
params = ` (${params})`
}
return `X${params}`
}).join(' | ') + ' |')
})
lines.push('') // file should end with a single newline character
fs.writeFileSync(`standards/${scope.id}.md`, lines.join('\n'), 'utf8')

const state = columns.filter((c) => versionsShown[c].isEffective).length ? '📜' : '✏️'
return {
type: 'doc',
label: scope.name,
id: scope.id,
fetchScopeTable(scope.uuid, scope.name, `standards/${scope.id}.md`).catch(
(e) => {
console.log(e)
}
)
return {
type: 'doc',
label: scope.name,
id: scope.id
}
})

var newSidebars = `module.exports = ${JSON.stringify(sidebarItems, null, ' ')}`
Expand Down
18 changes: 18 additions & 0 deletions populateClouds.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const fetch = require('node-fetch')
const fs = require('fs')

async function insertCloudTable(pathIn, pathOut) {
const template = fs.readFileSync(pathIn, 'utf8')
const response = await fetch(
`https://compliance.sovereignit.cloud/markdown/table`
)
const text = template.replace('<!--CLOUDS-->', await response.text())
fs.writeFileSync(pathOut, text, 'utf8')
}

insertCloudTable(
`standards/certification/overview.template.md`,
`standards/certification/overview.md`
).catch((e) => {
console.log(e)
})
24 changes: 0 additions & 24 deletions standards/certification/overview.md

This file was deleted.

14 changes: 14 additions & 0 deletions standards/certification/overview.template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!-- markdownlint-disable -->
# Certification

SCS certificates come with various scopes. See [Scopes and Versions](scopes-versions.md) for details.

## Becoming certified

In order for a cloud service offering to obtain a certificate, it has to conform to all standards of the respective scope, which will be tested at regular intervals, and the results of these tests will be made available publicly. For more details on how to become certified, please consult the corresponding [document](/standards/scs-0004-v1-achieving-certification).

## Compliant cloud environments

This is a list of clouds that we test on a nightly basis against the certificate scope _SCS-compatible IaaS_.

<!--CLOUDS-->
Loading