chore: update for API

This commit is contained in:
Dan Brodjieski
2026-05-18 09:47:00 -04:00
parent 155728cdfc
commit 3a7bb29628
21 changed files with 22 additions and 1420 deletions

View File

@@ -31,6 +31,14 @@ MODULE_PREFIX = (
)
OUTPUT_DIR = REPO_ROOT / "src" / "content" / "docs" / "api"
# Paths (relative to repo root) to exclude from documentation entirely.
# These are internal implementation packages, not public library API.
SKIP_PATHS = {
"src/mscp/generate",
"src/mscp/admin_utils",
"src/mscp/cli.py",
}
def run_git(*args: str) -> str:
result = subprocess.run(
@@ -54,6 +62,8 @@ def list_python_files() -> list[str]:
# entry-point shims like __main__.py that have no API surface anyway.
if Path(rel).name == "__main__.py":
continue
if any(rel == p or rel.startswith(p + "/") for p in SKIP_PATHS):
continue
files.append(rel)
return sorted(files)
@@ -158,14 +168,21 @@ def extract_dunder_all(tree: ast.Module) -> list[str]:
def parse_module(rel_path: str, source: str) -> ModuleDoc:
tree = ast.parse(source)
exports = extract_dunder_all(tree)
exports_set = set(exports) # non-empty only when __all__ is defined
functions: list[FunctionDoc] = []
classes: list[ClassDoc] = []
for node in tree.body:
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
if exports_set and node.name not in exports_set:
continue
func = parse_function(node)
if func is not None:
functions.append(func)
elif isinstance(node, ast.ClassDef):
if exports_set and node.name not in exports_set:
continue
cls = parse_class(node)
if cls is not None:
classes.append(cls)
@@ -182,7 +199,7 @@ def parse_module(rel_path: str, source: str) -> ModuleDoc:
module_docstring=ast.get_docstring(tree),
functions=functions,
classes=classes,
exports=extract_dunder_all(tree),
exports=exports,
)

View File

@@ -1,99 +0,0 @@
---
title: mscp.admin_utils.banner_generator
description: "Banner image generator for the macOS Security Compliance Project (mSCP)."
sidebar:
order: 1
---
> Source: [`src/mscp/admin_utils/banner_generator.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/admin_utils/banner_generator.py)
Banner image generator for the macOS Security Compliance Project (mSCP).
Produces per-platform banner images (macOS, iOS, visionOS) in light, dark,
and high-contrast (8 px stroke) modes by compositing the mSCP logo with
platform-specific text and a rounded colored divider.
Background removal uses a BFS flood-fill from image edges (``isolate_logo``).
Logo pixels are recolored per platform via ``change_color``.
Public entry point: ``generate_mscp_banners()``
Configuration keys consumed from ``config``:
images_dir — directory containing ``mscp_logo.png``; output is written here.
Output filename pattern:
mscp_banner_<platform>_<mode>.png
where platform ∈ {macos, ios, visionos} and mode ∈ {light, dark, both_8px}.
## Functions
### color_dist
```python
color_dist(a: tuple, b: tuple) -> int
```
### isolate_logo
```python
isolate_logo(logo_path: str, threshold: int=40) -> Image.Image
```
Remove the background of a logo image using a flood-fill from the edges.
Assumes the top-left pixel is representative of the background color.
Edge-reachable pixels within *threshold* color distance (sum of absolute
RGB channel differences) of that background are made fully transparent.
The result is cropped to the tightest bounding box of remaining opaque content.
**Args**
- **`logo_path`** — Path to the source image (any PIL-supported format).
- **`threshold`** — Maximum RGB channel distance to treat a pixel as background.
**Returns**
- RGBA Image with background removed and cropped to content bounds.
### font
```python
font(font_path: str, size: int, bold: bool=False, italic: bool=False) -> ImageFont.FreeTypeFont
```
### draw_text
```python
draw_text(draw: ImageDraw.ImageDraw, xy: tuple, text: str, fnt: ImageFont.FreeTypeFont, style: dict) -> None
```
### change_color
```python
change_color(image: Image.Image, old_color: tuple, new_color: tuple, tolerance: int=0) -> Image.Image
```
### generate_mscp_banners
```python
generate_mscp_banners(sp: Yaspin, args: argparse.Namespace) -> None
```
*Decorators:* `@conditional_inject_spinner()`
Generate MSCP banner images for all supported platforms and display modes.
Reads ``mscp_logo.png`` from ``config["images_dir"]``, removes its background,
recolors it per platform, and composites it with title text onto a transparent
RGBA canvas. Nine files are written in total (3 platforms × 3 modes).
**Args**
- **`sp`** — Yaspin spinner instance injected by ``@conditional_inject_spinner``.
- **`args`** — Parsed CLI arguments from argparse.

View File

@@ -1,45 +0,0 @@
---
title: mscp.admin_utils.build_baselines
description: "Bulk-rebuild every supported baseline."
sidebar:
order: 1
---
> Source: [`src/mscp/admin_utils/build_baselines.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/admin_utils/build_baselines.py)
Bulk-rebuild every supported baseline.
Wires up the ``mscp admin baselines`` subcommand: discovers all rules
for the requested platform, derives the set of benchmarks and tags
they cover, then drives `generate_baseline` once per
benchmark-and-platform pair plus once per remaining tag-and-platform
pair.
## Functions
### build_all_baselines
```python
build_all_baselines(args: argparse.Namespace) -> None
```
Regenerate every default baseline file for the configured platforms.
Clears `config["baseline_dir"]`, collects every rule for
`args.os_name` / `args.os_version`, derives the set of benchmarks and
tags from those rules, and then calls `generate_baseline` once per
discovered benchmark (per its own platform list) and once per
remaining tag for every supported platform in
`mscp_data["versions"]["platforms"]`. A small set of housekeeping tags
(``arm64``, ``i368``, ``inherent``, ``manual``, ``n_a``, ``none``,
``permanent``) is excluded from the second pass.
**Args**
- **`args`** *(argparse.Namespace)* — Parsed CLI arguments. Required fields: ``os_name``, ``os_version``. The function additionally sets ``tailor``, ``list_tags``, ``controls``, ``keyword``, and ``os_name`` on the namespace as it iterates — callers should treat the namespace as scratch space.
**Side Effects**
- Deletes the contents of the default baseline directory and writes
- new baseline YAML files into it.

View File

@@ -1,19 +0,0 @@
---
title: mscp.admin_utils
description: "Administrative utilities exposed via ``mscp admin``."
sidebar:
order: 0
---
> Source: [`src/mscp/admin_utils/__init__.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/admin_utils/__init__.py)
Administrative utilities exposed via ``mscp admin``.
Re-exports `build_all_baselines` (rebuilds every supported baseline) and
`add_new_rule` (interactive helper to scaffold a new rule YAML). Both are
wired up as `argparse` subcommands in `mscp.cli`.
## Re-exports (`__all__`)
`build_all_baselines`, `add_new_rule`, `generate_mscp_banners`

View File

@@ -1,39 +0,0 @@
---
title: mscp.admin_utils.rule_utilities
description: "Interactive helpers for working with rule YAML files."
sidebar:
order: 1
---
> Source: [`src/mscp/admin_utils/rule_utilities.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/admin_utils/rule_utilities.py)
Interactive helpers for working with rule YAML files.
Currently provides `add_new_rule`, which scaffolds a placeholder rule
file under the configured custom rules directory.
## Functions
### add_new_rule
```python
add_new_rule(args: argparse.Namespace) -> None
```
Scaffold a new placeholder rule YAML in the custom rules directory.
Prompts for a title and unique rule ID, builds a minimal
`Macsecurityrule` populated with placeholder values (mechanism
``"Configuration Profile"``, section ``"auditing"``, NIST references
empty), and serialises it to
``<custom_rules_dir>/<rule_id>.yaml`` for the user to fill in.
**Args**
- **`args`** *(argparse.Namespace)* — Parsed CLI arguments; only `os_name` is consumed (used for both `os_name` and `os_type` on the scaffolded rule).
**Side Effects**
- Writes a YAML file to disk and prompts on stdin via
- `sanitize_input`.

View File

@@ -16,45 +16,12 @@ the `Baseline`, `Profile`, and `Author` Pydantic models, along with class
methods to load baselines from YAML and write them back out.
## Re-exports (`__all__`)
`Author`, `Profile`, `Baseline`
## Classes
### BaseModelWithAccessors
```python
class BaseModelWithAccessors(BaseModel)
```
Pydantic base class with dict-style accessors.
Adds `get` plus ``__getitem__`` / ``__setitem__`` so subclasses can be
treated either as Pydantic models or as plain dict-like objects. Item
access is restricted to declared model fields to keep typos from
silently creating new attributes.
#### Methods
##### get
```python
get(self, attr: str, default: Any=None) -> Any
```
Return the value of `attr`, or `default` if it isn't set.
Unlike ``__getitem__``, this never raises and is not restricted to
declared model fields — it just delegates to `getattr`.
**Args**
- **`attr`** *(str)* — Attribute name to read.
- **`default`** *(Any)* — Value returned when ``attr`` is absent. Defaults to ``None``.
**Returns**
- **`Any`** — The attribute value, or ``default`` if no such attribute exists on the instance.
### Author
```python

View File

@@ -1,121 +0,0 @@
---
title: mscp.cli
description: "Command-line interface for mSCP."
sidebar:
order: 1
---
> Source: [`src/mscp/cli.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/cli.py)
Command-line interface for mSCP.
Defines `parse_cli`, the top-level entry point invoked from
:mod:`mscp.__main__`. Builds an `argparse` tree with subcommands
``baseline`` / ``guidance`` / ``mapping`` / ``scap`` / ``admin`` (the
last with its own nested utilities) and dispatches to the matching
function in `mscp.generate` or `mscp.admin_utils`.
## Classes
### Customparser
```python
class Customparser(argparse.ArgumentParser)
```
`argparse.ArgumentParser` that logs errors via `loguru`.
Overrides `error` so usage failures are routed through the mSCP logger
(instead of stderr) before the help text is printed and the process
exits with status 2.
#### Methods
##### error
```python
error(self, message: str) -> None
```
Log `message` via `loguru`, print help, and exit with status 2.
**Args**
- **`message`** *(str)* — Error message reported by `argparse`.
### SmartFormatter
```python
class SmartFormatter(argparse.HelpFormatter)
```
Help formatter with two minor tweaks for the mSCP CLI.
- Single-letter / single-form options are indented to align with the
long-form options for readability.
- Help strings prefixed with ``"R|"`` are emitted with their original
newlines preserved (a common ``argparse`` recipe for raw text).
## Functions
### get_macos_version
```python
get_macos_version() -> float
```
Return the running host's major macOS version as a float.
Used as the default for the ``--os_version`` flag so the CLI assumes
the current host's version unless overridden. Falls back to ``26.0``
when `platform.mac_ver` returns an empty string (e.g. when run on a
non-macOS host).
**Returns**
- **`float`** — Major version (e.g. ``15.0``), or ``26.0`` on a non-macOS host.
### validate_file
```python
validate_file(arg: str) -> Path | None
```
`argparse` type validator: ensure ``arg`` points at an existing file.
Used as the ``type=`` argument on flags that take a path. Logs an
error and calls `sys.exit` if the path doesn't resolve to a file.
**Args**
- **`arg`** *(str)* — Raw command-line argument value.
**Returns**
- Path | None: The validated `Path`, or never returns when the file is missing (process exits).
### parse_cli
```python
parse_cli() -> None
```
Build the mSCP argument parser, parse `sys.argv`, and dispatch.
Constructs the top-level parser plus the ``baseline``, ``guidance``,
``mapping``, ``scap``, and ``admin`` subcommands (each with its own
flags), applies log-verbosity overrides, validates the platform/OS
arguments (rejects unsupported macOS / iOS versions), and then calls
the subcommand's bound ``func`` with the parsed `argparse.Namespace`.
**Side Effects**
- Reads ``sys.argv``; configures the global mSCP logger;
- mutates the global `config` dict for ``output_dir`` / ``rules_dir``;
- may call `sys.exit` on validation failure.

View File

@@ -1,110 +0,0 @@
---
title: mscp.generate.baseline
description: "Baseline YAML generation for the macOS Security Compliance Project."
sidebar:
order: 1
---
> Source: [`src/mscp/generate/baseline.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/baseline.py)
Baseline YAML generation for the macOS Security Compliance Project.
Provides `generate_baseline`, which queries the rule library for a
given OS / keyword combination and writes a YAML baseline file.
Helper functions collect available tags and benchmarks, filter rules,
and handle the interactive tailoring workflow.
## Functions
### collect_tags_and_benchmarks
```python
collect_tags_and_benchmarks(rules: list[Macsecurityrule]) -> tuple[list[str], dict[str, set[str]]]
```
Collect all tags and benchmark-to-platform mappings from a rule list.
Iterates every rule's ``tags`` and ``platforms`` data to build a sorted
list of unique tags (with ``"all_rules"`` always appended) and a dict
mapping each benchmark name to the set of OS types that declare it.
**Args**
- **`rules`** *(list[Macsecurityrule])* — Rules to inspect.
**Returns**
- tuple[list[str], dict[str, set[str]]]: ``(sorted_tags, benchmark_platforms)`` where *benchmark_platforms* maps benchmark name → set of OS-type strings.
### collect_established_benchmarks
```python
collect_established_benchmarks(rules: list[Macsecurityrule]) -> list[str]
```
Attempts to collect all established benchmarks in the MSCP library. An established
benchmark is one where an ODV has been defined for a given benchmark.
**Args**
- **`rules`** *(list[Macsecurityrule])* — A list of collected rules from the library.
**Returns**
- **`list`** — A sorted set of discovered benchmarks
### print_keyword_summary
```python
print_keyword_summary(tags: list[str], benchmark_platforms: dict[str, set[str]]) -> None
```
Print available tags and benchmarks to stdout, then exit.
**Args**
- **`tags`** *(list[str])* — Sorted list of all available tag strings.
- **`benchmark_platforms`** *(dict[str, set[str]])* — Mapping of benchmark name to the set of OS-type strings on which it is defined.
### rule_has_benchmark_for_version
```python
rule_has_benchmark_for_version(rule: Macsecurityrule, keyword: str, os_type: str, os_version: str) -> bool
```
Return True if *rule* declares *keyword* as a benchmark for the given OS version.
**Args**
- **`rule`** *(Macsecurityrule)* — Rule to inspect.
- **`keyword`** *(str)* — Benchmark name to look for.
- **`os_type`** *(str)* — OS type string (e.g. ``"macos"``); ``"os"`` is normalised to ``"OS"`` before the lookup.
- **`os_version`** *(str)* — OS version string (e.g. ``"15"``).
**Returns**
- **`bool`** — ``True`` if the benchmark is listed under the rule's platforms entry for that OS type and version, ``False`` otherwise.
### generate_baseline
```python
generate_baseline(args: argparse.Namespace, admin=False) -> None
```
*Decorators:* `@logger.catch`
Generate a YAML baseline file for the specified OS and keyword.
Collects all rules matching ``args.keyword`` (tag or benchmark name),
optionally runs the interactive tailoring workflow, and writes the
resulting baseline YAML to disk.
**Args**
- **`args`** *(argparse.Namespace)* — Parsed CLI arguments. Expected attributes: ``os_name``, ``os_version``, ``keyword``, ``tailor``, ``list_tags``, ``controls``.
- **`admin`** *(bool)* — When ``True`` the output is written to the library's default baseline directory instead of the custom directory. Defaults to ``False``.

View File

@@ -1,59 +0,0 @@
---
title: mscp.generate.guidance
description: "Main guidance document orchestration for the macOS Security Compliance Project."
sidebar:
order: 1
---
> Source: [`src/mscp/generate/guidance.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/guidance.py)
Main guidance document orchestration for the macOS Security Compliance Project.
Provides `generate_guidance`, the top-level entry point that coordinates
profile generation, DDM declarations, compliance scripts, Excel output,
Markdown documents, JSON manifests, and AsciiDoc/PDF/HTML guidance documents
for a given baseline. `verify_signing_hash` validates a certificate hash
before profile signing.
## Functions
### verify_signing_hash
```python
verify_signing_hash(cert_hash: str) -> bool
```
Verify that *cert_hash* identifies an installed signing certificate.
Writes a temporary file, attempts to sign it with ``security cms -SZ``,
then removes the file.
**Args**
- **`cert_hash`** *(str)* — Subject Key ID hash of the certificate to verify.
**Returns**
- **`bool`** — ``True`` if signing succeeds, ``False`` otherwise.
### generate_guidance
```python
generate_guidance(sp: Yaspin, args: argparse.Namespace) -> None
```
*Decorators:* `@conditional_inject_spinner()`
Orchestrate all guidance artifacts for a given baseline.
Reads the baseline YAML and, based on ``args`` flags, delegates to the
appropriate sub-generators: configuration profiles, DDM declarations,
compliance scripts, Excel workbook, Markdown documents, JSON manifest,
and the primary AsciiDoc/PDF/HTML guidance document.
**Args**
- **`sp`** *(Yaspin)* — Spinner instance injected by `conditional_inject_spinner`.
- **`args`** *(argparse.Namespace)* — Parsed CLI arguments. Expected attributes: ``baseline``, ``os_name``, ``language``, ``dark``, ``hash``, ``reference``, ``logo``, ``audit_name``, ``profiles``, ``ddm``, ``script``, ``xlsx``, ``gary``, ``markdown``, ``manifest``, ``all``, ``consolidated_profile``, ``granular_profiles``.

View File

@@ -1,68 +0,0 @@
---
title: mscp.generate.guidance_support.ddm
description: "Declarative Device Management (DDM) artifact generation for mSCP."
sidebar:
order: 1
---
> Source: [`src/mscp/generate/guidance_support/ddm.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/guidance_support/ddm.py)
Declarative Device Management (DDM) artifact generation for mSCP.
Provides `generate_ddm`, which processes ``ddm_info`` fields from baseline
rules and writes DDM JSON configurations, assets, activations, and service
ZIP archives under a ``declarative/`` subdirectory of the build path.
## Functions
### generate_ddm_activation
```python
generate_ddm_activation(output_path: Path, identifier: str) -> None
```
Write a DDM activation JSON file that references a single configuration.
Derives the activation identifier from *identifier* by replacing
``"config"`` and ``"asset"`` with ``"activation"``, then appends the
JSON payload to *output_path*.
**Args**
- **`output_path`** *(Path)* — Destination file path (created or appended to).
- **`identifier`** *(str)* — Configuration or asset DDM identifier to activate.
### zip_directory
```python
zip_directory(zip_path: Path, folder_path: Path) -> None
```
Recursively compress *folder_path* into *zip_path*, preserving relative paths.
**Args**
- **`zip_path`** *(Path)* — Destination ZIP file path.
- **`folder_path`** *(Path)* — Directory to compress.
### generate_ddm
```python
generate_ddm(build_path: Path, baseline: Baseline, baseline_name: str) -> None
```
Generate DDM configuration, asset, and activation JSON files for *baseline*.
Iterates rules with ``ddm_info``, writing service configuration files and
ZIP archives (``com.apple.configuration.services.configuration-files``) or
standard declaration JSONs into ``<build_path>/declarative/{configurations,
assets,activations}/``. Skips non-Apple platforms and unknown services.
**Args**
- **`build_path`** *(Path)* — Root output directory for this baseline's artifacts.
- **`baseline`** *(Baseline)* — Baseline whose rules supply ``ddm_info`` payloads.
- **`baseline_name`** *(str)* — Baseline name used as part of DDM identifiers.

View File

@@ -1,257 +0,0 @@
---
title: mscp.generate.guidance_support.documents
description: "Guidance document rendering (AsciiDoc, PDF, HTML, Markdown) for mSCP."
sidebar:
order: 1
---
> Source: [`src/mscp/generate/guidance_support/documents.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/guidance_support/documents.py)
Guidance document rendering (AsciiDoc, PDF, HTML, Markdown) for mSCP.
Provides `generate_documents`, which renders a baseline through the main
Jinja template and optionally invokes AsciiDoctor to produce PDF and HTML
output. `render_template` performs the actual Jinja render. Helper Jinja
filters are also defined here: `group_ulify`, `group_ulify_md`,
`render_references`, `render_rules`, `render_rules_md`,
`replace_include_with_file_content`, `asciidoc_to_markdown`, and
`get_nested`.
## Functions
### group_ulify
```python
group_ulify(elements: list[str]) -> str
```
Converts a list of strings into a grouped unordered list (UL) format.
If the list contains the string "N/A", it returns "- N/A".
Otherwise, it sorts the list, groups elements by their prefix (before the first parenthesis),
and returns a string where each group is represented as a bullet point with its elements
separated by commas.
**Args**
- **`elements`** *(list[str])* — The list of strings to be converted.
**Returns**
- **`str`** — A string representing the grouped unordered list.
### group_ulify_md
```python
group_ulify_md(elements: list[str]) -> str
```
Convert a list of strings to a grouped ``<br />``-separated Markdown bullet list.
Like `group_ulify` but uses HTML ``<br />`` between groups for inline
Markdown rendering in tables.
**Args**
- **`elements`** *(list[str])* — Strings to group and format.
**Returns**
- **`str`** — ``"- N/A"`` if ``"N/A"`` is in *elements*, otherwise a ``<br />``-joined grouped bullet string.
### extract_from_title
```python
extract_from_title(title: str) -> str
```
Extract the text inside the first parenthesised group in *title*.
**Args**
- **`title`** *(str)* — String that may contain a ``(…)`` group.
**Returns**
- **`str`** — The content inside the first ``(…)``, or ``""`` if not found.
### render_references
```python
render_references(reference_set: Sequence[Dict[str, Any]]) -> str
```
Convert a sequence of dicts into AsciiDoc table rows (no header, no ``|===``).
**Args**
- **`reference_set`** *(Sequence[Dict[str, Any]])* — Dicts to render; list values are joined with ``"\n- "``.
**Returns**
- **`str`** — Newline-separated AsciiDoc cell rows, or ``""`` if *reference_set* is empty.
**Raises**
- **`TypeError`** — If any element of *reference_set* is not a dict.
### render_rules
```python
render_rules(rule_set: list[str]) -> str
```
Render a list of rule strings as newline-separated ``"- <rule>"`` lines.
**Args**
- **`rule_set`** *(list[str])* — Rule strings to render.
**Returns**
- **`str`** — Newline-joined bullet lines.
### render_rules_md
```python
render_rules_md(rule_set: list[str]) -> str
```
Render a list of rule strings as ``<br>``-joined ``"- <rule>"`` lines for Markdown.
**Args**
- **`rule_set`** *(list[str])* — Rule strings to render.
**Returns**
- **`str`** — ``<br>``-joined bullet lines.
### replace_include_with_file_content
```python
replace_include_with_file_content(text: str) -> str
```
Replace AsciiDoc ``include::`` directives with the content of the referenced file.
Files are resolved relative to the configured ``includes_dir``. Missing
files are logged and replaced with an HTML comment placeholder.
**Args**
- **`text`** *(str)* — AsciiDoc source that may contain ``include::<path>[]`` directives.
**Returns**
- **`str`** — Source with all ``include::`` directives replaced by file contents.
### asciidoc_to_markdown
```python
asciidoc_to_markdown(value: str) -> str
```
Convert a subset of AsciiDoc syntax to GitHub-flavoured Markdown.
Handles headers, NOTE/IMPORTANT admonitions, source code blocks,
tables (``|===``), unordered/ordered lists, block titles, and
``link:url[text]`` macros. Unsupported constructs are passed through
with links replaced and trailing whitespace stripped.
**Args**
- **`value`** *(str)* — AsciiDoc source text.
**Returns**
- **`str`** — Markdown-formatted text.
### get_nested
```python
get_nested(obj: Mapping[str, Any] | list, keys: list[str | int], default: Any=None) -> Any
```
Safely traverse a nested mapping / list using a sequence of keys or indices.
**Args**
- **`obj`** *(Mapping | list)* — Root object to traverse.
- **`keys`** *(list[str | int])* — Ordered path of dict keys or list indices.
- **`default`** — Value returned when any key/index is missing or the wrong type.
**Returns**
- **`Any`** — The value at the nested path, or *default* if unreachable.
### render_template
```python
render_template(output_file: Path, template_name: str, baseline: Baseline, b64logo: bytes, pdf_theme: str, html_css: str, logo_path: Path, os_name: str, version_info: dict[str, Any], show_all_tags: bool, custom: bool, template_dir: str, themes_dir: str, logo_dir: str, output_format: str='adoc', language: str='en') -> None
```
Render a Jinja template against *baseline* data and write to *output_file*.
Configures a Jinja ``Environment`` with all mSCP filters, installs
gettext translations for *language*, renders the template, and writes
the result as text.
**Args**
- **`output_file`** *(Path)* — Destination for the rendered output.
- **`template_name`** *(str)* — Filename of the template within *template_dir*.
- **`baseline`** *(Baseline)* — Baseline data model.
- **`b64logo`** *(bytes)* — Base64-encoded logo image bytes.
- **`pdf_theme`** *(str)* — AsciiDoctor-PDF theme filename.
- **`html_css`** *(str)* — CSS filename for HTML output.
- **`logo_path`** *(Path)* — Absolute path to the logo file.
- **`os_name`** *(str)* — Operating system name string.
- **`version_info`** *(dict[str, Any])* — OS/compliance version metadata.
- **`show_all_tags`** *(bool)* — Whether to render all tags in the document.
- **`custom`** *(bool)* — Whether the baseline uses a custom configuration.
- **`template_dir`** *(str)* — Path to the Jinja templates directory.
- **`themes_dir`** *(str)* — Path to the themes/styles directory.
- **`logo_dir`** *(str)* — Path to the images directory.
- **`output_format`** *(str)* — ``"adoc"`` (default) or ``"markdown"``.
- **`language`** *(str)* — BCP-47 language code for gettext lookup. Defaults to ``"en"``.
### generate_documents
```python
generate_documents(spinner: Yaspin, output_file: Path, baseline: Baseline, b64logo: bytes, pdf_theme: str, html_css: str, logo_path: Path, os_name: str, version_info: dict[str, Any], show_all_tags: bool=False, custom: bool=False, output_format: str='adoc', language: str='en') -> None
```
Render guidance documents and, for AsciiDoc output, invoke AsciiDoctor.
Selects standard or custom template/theme directories, calls
`render_template`, then (when *output_format* is ``"adoc"``) runs
``bundle exec asciidoctor`` and ``bundle exec asciidoctor-pdf`` to
produce HTML and PDF output.
**Args**
- **`spinner`** *(Yaspin)* — Spinner for progress feedback.
- **`output_file`** *(Path)* — Destination ``.adoc`` or ``.md`` file.
- **`baseline`** *(Baseline)* — Baseline data model.
- **`b64logo`** *(bytes)* — Base64-encoded logo image bytes.
- **`pdf_theme`** *(str)* — AsciiDoctor-PDF theme filename.
- **`html_css`** *(str)* — CSS filename for HTML output.
- **`logo_path`** *(Path)* — Absolute path to the logo file.
- **`os_name`** *(str)* — Operating system name string.
- **`version_info`** *(dict[str, Any])* — OS/compliance version metadata.
- **`show_all_tags`** *(bool)* — Whether to render all tags. Defaults to ``False``.
- **`custom`** *(bool)* — Whether to use the custom template directory. Defaults to ``False``.
- **`output_format`** *(str)* — ``"adoc"`` (default) or ``"markdown"``.
- **`language`** *(str)* — BCP-47 language code. Defaults to ``"en"``.

View File

@@ -1,88 +0,0 @@
---
title: mscp.generate.guidance_support.excel
description: "Excel workbook generation for mSCP baselines."
sidebar:
order: 1
---
> Source: [`src/mscp/generate/guidance_support/excel.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/guidance_support/excel.py)
Excel workbook generation for mSCP baselines.
Provides `generate_excel`, which converts a baseline to a formatted
``.xlsx`` workbook with auto-fitted columns, bold headers, wrapped text,
and an Excel table style. Helper functions handle column expansion,
list formatting, and cell-width calculation.
## Functions
### auto_fit_columns
```python
auto_fit_columns(sheet, threshold_length: int=120, buffer: int=2, wrap_multiline: bool=True)
```
Auto-fit width of each column in `sheet` based on the longest line per cell.
- threshold_length: max width to set for any column (your cap).
- buffer: add a few extra characters of padding.
- wrap_multiline: optionally enable wrapText for cells that contain newlines.
### format_list_cell
```python
format_list_cell(x, unwrap_single=True, sep='\n')
```
Format a cell that may be a list:
- Empty list -> pd.NA
- Single-item list (unwrap_single=True) -> that item
- Multi-item list -> newline-separated string (items coerced to string)
- Non-list values returned unchanged
### expand_dict_column
```python
expand_dict_column(df, col, unwrap_single_lists=True, list_sep='\n', drop_original=True, flatten_sep='.')
```
Expand dictionaries found in df[col] into new columns named '{col}:{keypath}',
flattening nested keys with `flatten_sep`. Lists encountered inside dict values
are formatted per `format_list_cell`. Original column can be dropped.
### expand_dicts_and_format_lists
```python
expand_dicts_and_format_lists(df, unwrap_single_lists=True, list_sep='\n', drop_original_dict_cols=True, flatten_sep='.')
```
Process the entire DataFrame:
1) For every column that contains dictionaries in any row:
- Expand into '{col}:{keypath}' columns.
- Drop the original dict column (configurable).
- Format lists found inside those dict values.
2) For every remaining column that contains lists in any row:
- Unwrap single-item lists.
- Join multi-item lists with `list_sep`.
### generate_excel
```python
generate_excel(file_out: Path, baseline: Baseline) -> None
```
Generate a formatted Excel workbook from *baseline* rule data.
Converts the baseline to a DataFrame, drops internal-only columns,
expands nested dict/list columns, reorders and uppercases headers,
and writes the result to *file_out* with bold headers, top-aligned
cells, auto-fitted column widths, and an Excel table style.
**Args**
- **`file_out`** *(Path)* — Destination ``.xlsx`` path.
- **`baseline`** *(Baseline)* — Baseline whose rules populate the workbook.

View File

@@ -1,21 +0,0 @@
---
title: mscp.generate.guidance_support
description: "Guidance artifact sub-generators used by `generate_guidance`."
sidebar:
order: 0
---
> Source: [`src/mscp/generate/guidance_support/__init__.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/guidance_support/__init__.py)
Guidance artifact sub-generators used by `generate_guidance`.
Re-exports: `generate_ddm` (DDM JSON/ZIP artifacts), `generate_documents`
(AsciiDoc / PDF / HTML / Markdown), `generate_excel` (Excel workbook),
`generate_profiles` (configuration profiles), `generate_script` and
`generate_restore_script` (compliance shell scripts), and
`generate_manifest` (JSON manifest).
## Re-exports (`__all__`)
`generate_ddm`, `generate_documents`, `generate_excel`, `generate_profiles`, `generate_script`, `generate_restore_script`, `generate_manifest`

View File

@@ -1,35 +0,0 @@
---
title: mscp.generate.guidance_support.manifest
description: "JSON manifest generation for mSCP baselines."
sidebar:
order: 1
---
> Source: [`src/mscp/generate/guidance_support/manifest.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/guidance_support/manifest.py)
JSON manifest generation for mSCP baselines.
Provides `generate_manifest`, which serialises baseline metadata and
per-rule details (references, check command, fix payload) into a single
JSON file used by downstream tooling to identify and audit rules.
## Functions
### generate_manifest
```python
generate_manifest(build_path: Path, baseline_name: str, baseline) -> None
```
Write a JSON manifest summarising the baseline and all its rules.
The manifest includes platform metadata, release info, plist and log
paths, and a list of rules with their IDs, titles, references, tags,
check commands, and fix payloads (mobileconfig, DDM, or script).
**Args**
- **`build_path`** *(Path)* — Output directory; the manifest is written as ``<build_path>/<baseline_name>.json``.
- **`baseline_name`** *(str)* — Name of the baseline (used for file naming and plist/log path strings).
- **`baseline`** — Loaded ``Baseline`` object containing profiles and platform info.

View File

@@ -1,74 +0,0 @@
---
title: mscp.generate.guidance_support.profiles
description: "Configuration profile (mobileconfig) generation for mSCP baselines."
sidebar:
order: 1
---
> Source: [`src/mscp/generate/guidance_support/profiles.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/guidance_support/profiles.py)
Configuration profile (mobileconfig) generation for mSCP baselines.
Provides `generate_profiles`, which groups rule payload data by type and
writes unsigned (and optionally signed) ``.mobileconfig`` files and
preferences plists. `get_payload_content_by_type` groups rule payloads;
`sign_config_profile` CMS-signs a profile using a certificate hash.
## Functions
### get_payload_content_by_type
```python
get_payload_content_by_type(rules: list[Macsecurityrule]) -> dict[str, list[dict[str, Any]]]
```
Group mobileconfig payload content by payload type across a list of rules.
**Args**
- **`rules`** *(list[Macsecurityrule])* — Rules to inspect for ``mobileconfig_info``.
**Returns**
- dict[str, list[dict[str, Any]]]: Mapping of ``payload_type`` → list of ``payload_content`` dicts (duplicates are warned and skipped).
### sign_config_profile
```python
sign_config_profile(in_file: Path, out_file: Path, cert_hash: str) -> None
```
CMS-sign a configuration profile using the certificate identified by *cert_hash*.
**Args**
- **`in_file`** *(Path)* — Unsigned ``.mobileconfig`` file to sign.
- **`out_file`** *(Path)* — Destination path for the signed profile.
- **`cert_hash`** *(str)* — Subject Key ID hash of the signing certificate.
### generate_profiles
```python
generate_profiles(build_path: Path, baseline_name: str, baseline: Baseline, signing: bool=False, hash_value: str='', consolidated: bool=False, granular: bool=False) -> None
```
*Decorators:* `@logger.catch`
Generate mobileconfig profiles from baseline rules and write them to *build_path*.
Groups rule payload content by type, writes per-type unsigned profiles,
optionally produces signed copies, a consolidated all-in-one profile, and
per-setting granular profiles. Skips non-Apple platforms.
**Args**
- **`build_path`** *(Path)* — Root output directory for this baseline's artifacts.
- **`baseline_name`** *(str)* — Baseline name used in identifiers and filenames.
- **`baseline`** *(Baseline)* — Baseline containing profile rules with payload info.
- **`signing`** *(bool)* — Sign generated profiles with *hash_value*. Defaults to ``False``.
- **`hash_value`** *(str)* — Certificate hash for signing. Defaults to ``""``.
- **`consolidated`** *(bool)* — Write a single profile containing all settings. Defaults to ``False``.
- **`granular`** *(bool)* — Write individual profiles per setting. Defaults to ``False``.

View File

@@ -1,127 +0,0 @@
---
title: mscp.generate.guidance_support.script
description: "Compliance and restore shell script generation for mSCP baselines."
sidebar:
order: 1
---
> Source: [`src/mscp/generate/guidance_support/script.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/guidance_support/script.py)
Compliance and restore shell script generation for mSCP baselines.
Provides `generate_script` (audit compliance script) and
`generate_restore_script` (defaults-restore script), both rendered from
Jinja templates. `generate_audit_plist` writes the companion audit plist.
Jinja filter helpers `group_ulify`, `generate_log_reference`, and
`quotify` are also defined here.
## Functions
### group_ulify
```python
group_ulify(elements: list[str]) -> str
```
Converts a list of strings into a grouped unordered list format.
This function is used as a Jinja filter to format a list of strings.
It groups the elements by their prefix (before the first parenthesis),
sorts them, and then formats them into a string with each group
represented as an unordered list.
**Args**
- **`elements`** *(list[str])* — The list of strings to be formatted.
**Returns**
- **`str`** — A formatted string representing the grouped unordered list.
- If the input is "N/A", it returns "- N/A".
### generate_log_reference
```python
generate_log_reference(rule: Macsecurityrule, reference: str) -> list[str] | str
```
Generate the log reference ID based on the rule and reference type.
**Note**
> This is used as a Jinja filter in the script template.
### quotify
```python
quotify(fix_code: str) -> str
```
Escape single quotes and format percentages for Bash.
**Note**
> This is used as a Jinja filter in the script template.
### generate_audit_plist
```python
generate_audit_plist(build_path: Path, baseline_name: str, baseline: Baseline) -> None
```
Write the default audit plist (``org.<baseline_name>.audit.plist``).
Creates a plist where each non-supplemental rule ID maps to
``{"exempt": False}``, used as the initial state for compliance auditing.
**Args**
- **`build_path`** *(Path)* — Root output directory; plist goes in ``preferences/``.
- **`baseline_name`** *(str)* — Baseline name used in the plist filename and ``/Library/Preferences`` path.
- **`baseline`** *(Baseline)* — Baseline whose rules populate the plist keys.
### generate_script
```python
generate_script(build_path: Path, baseline_name: str, audit_name: str, baseline: Baseline, log_reference: str, current_version_data: dict) -> None
```
Render and write the compliance audit shell script for *baseline*.
Uses the ``compliance_script.sh.jinja`` template and also calls
`generate_audit_plist`. Skips non-Unix platforms.
**Args**
- **`build_path`** *(Path)* — Output directory; script written as ``<baseline_name>_compliance.sh`` with mode ``0755``.
- **`baseline_name`** *(str)* — Baseline name used in filenames and template variables.
- **`audit_name`** *(str)* — Audit identifier string passed to the template.
- **`baseline`** *(Baseline)* — Loaded baseline object.
- **`log_reference`** *(str)* — Log reference key (e.g. ``"default"`` or a framework name) passed to the template.
- **`current_version_data`** *(dict)* — Version metadata for the OS/baseline.
### generate_restore_script
```python
generate_restore_script(build_path: Path, baseline_name: str, audit_name: str, baseline: Baseline, log_reference: str, current_version_data: dict) -> None
```
Render and write the restore shell script for *baseline* (if applicable).
Uses the ``restore_script.sh.jinja`` template. Only writes the file if at
least one rule has a ``default_state`` value, and skips non-Unix platforms.
**Args**
- **`build_path`** *(Path)* — Output directory; script written as ``<baseline_name>_restore.sh`` with mode ``0755``.
- **`baseline_name`** *(str)* — Baseline name used in filenames and template variables.
- **`audit_name`** *(str)* — Audit identifier string passed to the template.
- **`baseline`** *(Baseline)* — Loaded baseline object.
- **`log_reference`** *(str)* — Log reference key passed to the template.
- **`current_version_data`** *(dict)* — Version metadata for the OS/baseline.

View File

@@ -1,21 +0,0 @@
---
title: mscp.generate
description: "Baseline, guidance, and artifact generation entry points for mSCP."
sidebar:
order: 0
---
> Source: [`src/mscp/generate/__init__.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/__init__.py)
Baseline, guidance, and artifact generation entry points for mSCP.
Re-exports the top-level generator functions: `generate_baseline`
(YAML baseline files), `generate_guidance` (human-readable guidance
documents), `generate_mapping` (control-mapping reports),
`generate_scap` (SCAP/XCCDF content), `generate_localize_template`
and `generate_mo_from_json` (localization support files).
## Re-exports (`__all__`)
`generate_baseline`, `generate_guidance`, `generate_mapping`, `generate_scap`, `generate_localize_template`, `generate_mo_from_json`

View File

@@ -1,53 +0,0 @@
---
title: mscp.generate.mapping
description: "Control-framework mapping and custom baseline generation for mSCP."
sidebar:
order: 1
---
> Source: [`src/mscp/generate/mapping.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/mapping.py)
Control-framework mapping and custom baseline generation for mSCP.
Provides `generate_mapping`, which reads a CSV cross-walk between a known
security framework (e.g. NIST 800-53) and one or more target frameworks,
annotates matching rules with the mapped controls, writes per-rule YAML
files, and generates a custom baseline for each mapped framework column.
## Functions
### update_rule_with_custom_references
```python
update_rule_with_custom_references(rule: Macsecurityrule, references: list[str], reference_source: str) -> None
```
Update a rule with custom references.
**Args**
- **`rule`** *(Macsecurityrule)* — The rule to update.
- **`references`** *(List[str])* — The references to add.
- **`reference_source`** *(str)* — The reference source to map references to.
### generate_mapping
```python
generate_mapping(sp: Yaspin, args: argparse.Namespace) -> None
```
*Decorators:* `@conditional_inject_spinner()`
Map rules to a target framework via a CSV cross-walk and write custom baselines.
For each non-source column in the CSV, identifies rules whose
``args.framework`` references intersect the CSV rows, annotates them
with the mapped target controls, serializes updated rule YAML files,
and creates a custom baseline YAML for that column.
**Args**
- **`sp`** *(Yaspin)* — Spinner instance injected by `conditional_inject_spinner`.
- **`args`** *(argparse.Namespace)* — Parsed CLI arguments. Expected attributes: ``os_name``, ``os_version``, ``csv``, ``framework``.

View File

@@ -1,69 +0,0 @@
---
title: mscp.generate.scap
description: "SCAP 1.4 / XCCDF / OVAL content generation for the macOS Security Compliance Project."
sidebar:
order: 1
---
> Source: [`src/mscp/generate/scap.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/scap.py)
SCAP 1.4 / XCCDF / OVAL content generation for the macOS Security Compliance Project.
Provides `generate_scap`, which builds an XCCDF benchmark with profiles and
rules, an OVAL definitions document with shell-command tests, and (for macOS)
wraps them into a SCAP 1.4 data-stream XML file. Standalone XCCDF-only and
OVAL-only outputs are also supported.
## Functions
### pretty_format_xml
```python
pretty_format_xml(xml_string: str) -> str
```
Format XML using minidom, without extra blank lines.
### disa_stig_rules
```python
disa_stig_rules(stig_id, stig)
```
Extract the SRG title and Rule ID prefix for a given STIG ID from raw STIG XML text.
Searches the raw XML string for a ``<title>SRG-…</title>`` element and
the matching ``Rule id`` attribute adjacent to *stig_id*, then returns
them joined by ``", "``.
**Args**
- **`stig_id`** *(str)* — STIG rule identifier to search for (e.g. ``"SV-257502r858765_rule"``).
- **`stig`** *(str)* — Raw STIG XML text.
**Returns**
- **`str`** — ``"<SRG-title>, <RuleID-prefix>"`` if both are found; partial or empty string otherwise.
### generate_scap
```python
generate_scap(sp: Yaspin, args: argparse.Namespace) -> None
```
*Decorators:* `@conditional_inject_spinner()`
Generate SCAP, XCCDF, or OVAL output for the specified OS and baseline.
Collects all rules, builds XCCDF profiles and rules with inline OVAL
shell-command checks, and writes the result as a SCAP 1.4 data-stream
(macOS only), a standalone XCCDF, or a standalone OVAL file depending
on ``args``.
**Args**
- **`sp`** *(Yaspin)* — Spinner instance injected by `conditional_inject_spinner`.
- **`args`** *(argparse.Namespace)* — Parsed CLI arguments. Expected attributes: ``os_name``, ``os_version``, ``baseline``, ``list_tags``, ``oval``, ``xccdf``, ``disa_stig``.

View File

@@ -1,73 +0,0 @@
---
title: mscp.generate.translation
description: "Localization template and compiled message-object generation for mSCP."
sidebar:
order: 1
---
> Source: [`src/mscp/generate/translation.py`](https://github.com/usnistgov/macos_security/blob/dev_2.0/src/mscp/generate/translation.py)
Localization template and compiled message-object generation for mSCP.
Provides `generate_localize_template` (builds a ``messages.pot``-style JSON
from section YAML, Jinja templates, and rule strings) and `generate_mo_from_json`
(compiles a translated JSON file to a Babel ``.mo`` / ``.po`` pair).
## Functions
### extract_trans_text
```python
extract_trans_text(template: str) -> list[str]
```
Extract translatable strings from ``{% trans %}…{% endtrans %}`` blocks.
Strips embedded ``{{ … }}`` expressions, leading table-pipe markers,
and excess whitespace from each captured chunk, then de-duplicates
and drops empty results.
**Args**
- **`template`** *(str)* — Raw Jinja template source.
**Returns**
- **`list[str]`** — Unique non-empty translatable strings found in the template.
### generate_localize_template
```python
generate_localize_template(args: argparse.Namespace) -> None
```
Build a JSON translation template from section, template, and rule strings.
Collects translatable strings from section YAML files (``name`` /
``description``), Jinja templates (``{% trans %}`` blocks), and rule YAML
files (``title`` / ``discussion``), then writes them as a context-keyed
JSON file suitable for hand-translation or machine translation.
**Args**
- **`args`** *(argparse.Namespace)* — Parsed CLI arguments. Expected attributes: ``os_name``, ``os_version``, ``domain``, ``output``.
### generate_mo_from_json
```python
generate_mo_from_json(args: argparse.Namespace) -> None
```
Compile a translated JSON file to a Babel ``.mo`` and ``.po`` pair.
Reads a translated JSON mapping (``{ context: { "en": …, "<locale>": … } }``),
builds a Babel catalog for the target locale, and writes both a binary
``.mo`` and a human-readable ``.po`` file under
``<output_dir>/locale/<locale>/LC_MESSAGES/``.
**Args**
- **`args`** *(argparse.Namespace)* — Parsed CLI arguments. Expected attributes: ``json_file``, ``domain``, ``locale``, ``mo_file``, ``use_fuzzy``.

View File

@@ -22,7 +22,3 @@ mSCP log output should enable it (typically via `set_logger`).
## Re-exports (`__all__`)
`Baseline`, `Macsecurityrule`, `LoguruFormatter`, `Payload`, `RuleLibrary`, `config`, `append_text`, `create_csv`, `create_plist`, `create_yaml`, `make_dir`, `open_csv`, `open_file`, `open_plist`, `open_yaml`, `remove_dir`, `remove_dir_contents`, `remove_file`, `run_command`, `baseline`, `guidance`, `mapping`, `parse_cli`, `validate_yaml_file`, `set_logger`, `translation`
## Modules
- [`cli`](cli/)