diff --git a/.goreleaser.yaml b/.goreleaser.yaml index aecbf128..664aeb9c 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -24,12 +24,6 @@ builds: - "-X github.com/complytime/complyctl/internal/version.gitTreeState={{ .GitTreeState }}" - "-X github.com/complytime/complyctl/internal/version.commit={{ .Commit }}" - "-X github.com/complytime/complyctl/internal/version.buildDate={{ .Date }}" - - id: openscap-plugin - binary: openscap-plugin - dir: ./cmd/openscap-plugin - main: . - goos: - - linux archives: - format: tar.gz diff --git a/.specify/feature.json b/.specify/feature.json new file mode 100644 index 00000000..80e74f39 --- /dev/null +++ b/.specify/feature.json @@ -0,0 +1,3 @@ +{ + "feature_directory": "specs/005-rpm-packaging-ci" +} diff --git a/AGENTS.md b/AGENTS.md index 321e7be5..985131e8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,6 +3,7 @@ Auto-generated from all feature plans. Last updated: 2026-04-21 ## Active Technologies +- Go 1.25 + go-rpm-macros, Packit, Testing Farm (TMT/FMF) (005-rpm-packaging-ci) - Go 1.25 (complyctl root `go.mod`) (004-providers-repository-split) @@ -22,6 +23,7 @@ tests/ Go 1.25 (complyctl root `go.mod`): Follow standard conventions ## Recent Changes +- 005-rpm-packaging-ci: Added Go 1.25 + go-rpm-macros, Packit, Testing Farm (TMT/FMF) - 004-providers-repository-split: Providers (openscap, ampel) migrated to `complytime-providers`; `pkg/plugin/` renamed to `pkg/provider/`; all "plugin" terminology updated to "provider" diff --git a/Makefile b/Makefile index 2abf6922..b6424511 100644 --- a/Makefile +++ b/Makefile @@ -12,10 +12,6 @@ GO_LD_EXTRAFLAGS := -X github.com/complytime/complyctl/internal/version.version= MAN_COMPLYCTL = docs/man/complyctl.md MAN_COMPLYCTL_OUTPUT = docs/man/complyctl.1 -MAN_OPENSCAP_PROVIDER = docs/man/complyctl-openscap-provider.md -MAN_OPENSCAP_PROVIDER_OUTPUT = docs/man/complyctl-openscap-provider.7 -MAN_OPENSCAP_CONF = docs/man/c2p-openscap-manifest.md -MAN_OPENSCAP_CONF_OUTPUT = docs/man/c2p-openscap-manifest.5 ##@ Proto @@ -74,9 +70,8 @@ build-behavioral-report: prep-build-dir ## build behavioral report tool (go test ##@ Packaging man: ## generate man pages - mkdir -p $(dir $(MAN_COMPLYCTL_OUTPUT)) $(dir $(MAN_OPENSCAP_CONF_OUTPUT)) + mkdir -p $(dir $(MAN_COMPLYCTL_OUTPUT)) pandoc -s -t man $(MAN_COMPLYCTL) -o $(MAN_COMPLYCTL_OUTPUT) - pandoc -s -t man $(MAN_OPENSCAP_CONF) -o $(MAN_OPENSCAP_CONF_OUTPUT) ##@ Environment diff --git a/complyctl.spec b/complyctl.spec index c0c754c8..5a2e1c24 100644 --- a/complyctl.spec +++ b/complyctl.spec @@ -3,13 +3,12 @@ %global goipath github.com/complytime/complyctl %global base_url https://%{goipath} %global app_dir complytime -%global gopath %{_builddir}/go %global debug_package %{nil} Name: complyctl Version: 0.0.8 -Release: 0%{?dist} -Summary: Gemara-native compliance scanning CLI with pluggable providers +Release: 1%{?dist} +Summary: Compliance scanning CLI for OSCAL-based assessment workflows License: Apache-2.0 URL: %{base_url} Source0: %{base_url}/archive/refs/tags/v%{version}.tar.gz @@ -24,20 +23,13 @@ BuildRequires: go-rpm-macros graphs, dispatches scans to providers via gRPC, and produces compliance reports (EvaluationLog, OSCAL, Markdown, SARIF). -%package openscap-provider -Summary: OpenSCAP scanning provider for complyctl -Requires: %{name}%{?_isa} = %{version}-%{release} -Requires: scap-security-guide -%description openscap-provider -openscap-provider is a scanning provider that extends complyctl with OpenSCAP -evaluation capabilities. It communicates via gRPC (Generate, Scan, HealthCheck -RPCs) and follows the complyctl-provider-* discovery convention. +Providers are distributed separately via the complytime-providers package. %prep %goprep -k %build -BUILD_DATE_GO=$(date -u +'%Y-%m-%dT%H:%M:%SZ') +BUILD_DATE_GO=$(date -u +'%%Y-%%m-%%dT%%H:%%M:%%SZ') # Set up environment variables and flags to build properly and securely %set_build_flags @@ -55,38 +47,37 @@ export GO111MODULE=on GO_BUILD_BINDIR=./bin mkdir -p ${GO_BUILD_BINDIR} -# Not calling the macro for more control on go env variables -go build -buildmode=pie -o ${GO_BUILD_BINDIR}/ -ldflags="${GO_LD_EXTRAFLAGS}" ./cmd/... - -# Build openscap provider (separate Go module) -cd cmd/openscap-plugin -go build -buildmode=pie -o ../../${GO_BUILD_BINDIR}/complyctl-provider-openscap -ldflags="${GO_LD_EXTRAFLAGS}" . -cd ../.. +# Build only the complyctl binary +go build -buildmode=pie -o ${GO_BUILD_BINDIR}/complyctl -ldflags="${GO_LD_EXTRAFLAGS}" ./cmd/complyctl %install install -d %{buildroot}%{_bindir} install -d -m 0755 %{buildroot}%{_libexecdir}/%{app_dir}/providers +install -d %{buildroot}%{_mandir}/man1 install -p -m 0755 bin/complyctl %{buildroot}%{_bindir}/complyctl -install -p -m 0755 bin/complyctl-provider-openscap %{buildroot}%{_libexecdir}/%{app_dir}/providers/complyctl-provider-openscap +install -p -m 0644 docs/man/complyctl.1 %{buildroot}%{_mandir}/man1/complyctl.1 %check # Run unit tests go test -mod=vendor -race -v ./... -cd cmd/openscap-plugin && go test -mod=vendor -race -v ./... -cd ../.. %files %attr(0755, root, root) %{_bindir}/complyctl -%license LICENSE +%{_mandir}/man1/complyctl.1* +%license LICENSE vendor/modules.txt +%doc README.md %dir %{_libexecdir}/%{app_dir} %dir %{_libexecdir}/%{app_dir}/providers -%files openscap-provider -%attr(0755, root, root) %{_libexecdir}/%{app_dir}/providers/complyctl-provider-openscap -%license LICENSE - %changelog +* Fri Apr 24 2026 Marcus Burghardt - 0.0.8-1 +- Simplify spec for core-only delivery after provider split +- Remove openscap-provider sub-package (moved to complytime-providers) +- Add complyctl.1 man page +- Add vendor/modules.txt for automatic bundled provides generation +- Build only complyctl binary from cmd/complyctl + * Wed Jul 9 2025 Marcus Burghardt - 0.0.8-1 - Bump to upstream version v0.0.8 diff --git a/docs/RELEASE_PROCESS.md b/docs/RELEASE_PROCESS.md index 9d2fd8b9..190f8e69 100644 --- a/docs/RELEASE_PROCESS.md +++ b/docs/RELEASE_PROCESS.md @@ -31,9 +31,13 @@ Tests relevant for releases are incorporated in CI tests for every PR. Releases are currently expected every three weeks. Project maintainers always discuss and agree on releases. Therefore, some releases may be triggered a bit earlier or later when necessary. -## Fedora Package +## Fedora Packages -Once a new release is out, the [Fedora Package](https://src.fedoraproject.org/rpms/complyctl) also needs to be updated. +After the repository split, complyctl and complytime-providers are independent Fedora packages with separate release cycles. + +### complyctl + +Once a new complyctl release is out, the [Fedora Package](https://src.fedoraproject.org/rpms/complyctl) also needs to be updated. The process is automated by [Packit](https://packit.dev/docs/fedora-releases-guide) according to [.packit.yaml](https://github.com/complytime/complyctl/blob/main/.packit.yaml) configuration file and should only demand a PR review from a Fedora package [maintainer](https://src.fedoraproject.org/rpms/complyctl) @@ -41,6 +45,16 @@ This automation will create PRs for the specified branches. Once the PRs are rev - [Koji builds](https://koji.fedoraproject.org/koji/packageinfo?packageID=42298) will be created - [Bodhi updates](https://bodhi.fedoraproject.org/updates/?packages=complyctl) will be submitted +### complytime-providers + +The [complytime-providers](https://github.com/complytime/complytime-providers) repository has its own independent release and packaging pipeline. It produces two sub-packages: +- `complytime-providers-openscap` -- OpenSCAP scanning provider +- `complytime-providers-ampel` -- Ampel scanning provider + +The process is also automated by Packit via the `.packit.yaml` in the complytime-providers repository. + +> **Note:** The complytime-providers Fedora package requires a one-time [Fedora package review](https://docs.fedoraproject.org/en-US/package-maintainers/Joining_the_Package_Maintainers/) before the automation can function. Once approved, the Packit automation operates identically to complyctl. + ### Preparation (only necessary for Manual Process) To update a Fedora package, it is ultimately necessary to be a member of Fedora Packager group. diff --git a/docs/man/c2p-openscap-manifest.5 b/docs/man/c2p-openscap-manifest.5 deleted file mode 100644 index fc489c80..00000000 --- a/docs/man/c2p-openscap-manifest.5 +++ /dev/null @@ -1,180 +0,0 @@ -.\" Automatically generated by Pandoc 3.1.11.1 -.\" -.TH "C2P\-OPENSCAP\-MANIFEST.JSON" "5" "June 2025" "complyctl OpenSCAP Plugin Configuration" "" -.SH NAME -c2p\-openscap\-manifest.json \- Configuration file for the OpenSCAP -plugin used by complyctl -.SH DESCRIPTION -This file defines the metadata and runtime configuration options for the -\f[CR]openscap\-plugin\f[R], a plugin to be used with -\f[CR]complyctl\f[R]. -.PP -It is a JSON\-formatted file typically installed at: -.PP -\f[B]/usr/share/complyctl/plugins/c2p\-openscap\-manifest.json\f[R] -.PP -Some configuration options used by \f[CR]openscap\-plugin\f[R] can be -overridden by using a drop\-in file with the same name in -\[lq]\f[CR]/etc/complyctl/config.d/\f[R]\[rq]: -.PP -\f[B]/etc/complyctl/config.d/c2p\-openscap\-manifest.json\f[R] -.PP -The easiest way to create a drop\-in file is copying -\f[B]/usr/share/complyctl/plugins/c2p\-openscap\-manifest.json\f[R] and -defining the \f[CR]default\f[R] values. -Any other content can be removed to keep the drop\-in file clean. -See \f[B]CONFIGURATION OPTIONS\f[R] and \f[B]EXAMPLES\f[R] sections for -more details. -.PP -For some specific cases, it is also possible to inform a custom -configuration directory to override \f[CR]/etc/complyctl/config.d\f[R]. -For example, the following command will try to locate and read custom -settings from manifest files hosted in \f[CR]/tmp/plugins\-conf\f[R] -instead of \f[CR]/etc/complyctl/config.d\f[R]: -.PP -\f[CR]complyctl generate \-\-plugin\-config /tmp/plugins\-conf\f[R] -.PP -See complyctl(1) for more details about the available options. -.SH FILE FORMAT -The configuration is a single JSON object with the following top\-level -keys: -.IP \[bu] 2 -\f[CR]metadata\f[R]: General plugin information -.IP \[bu] 2 -\f[CR]executablePath\f[R]: Name or path of the plugin binary -.IP \[bu] 2 -\f[CR]sha256\f[R]: The checksum of the binary (used for integrity -checks) -.IP \[bu] 2 -\f[CR]configuration\f[R]: An array of runtime configuration options -.SH FIELDS -.SS metadata -.IP -.EX -{ - \[dq]id\[dq]: \[dq]openscap\[dq], - \[dq]description\[dq]: \[dq]My openscap plugin\[dq], - \[dq]version\[dq]: \[dq]0.0.1\[dq], - \[dq]types\[dq]: [ \[dq]pvp\[dq] ] -} -.EE -.SS executablePath -Path or name of the plugin binary to execute. -Typically just: -.IP -.EX -\[dq]executablePath\[dq]: \[dq]openscap\-plugin\[dq] -.EE -.SS sha256 -SHA256 checksum of the plugin binary, used for runtime verification. -.SS configuration -A list of supported configuration parameters for the plugin. -.PP -Each entry includes: -.IP \[bu] 2 -name: The name of the parameter -.IP \[bu] 2 -description: Explanation of its purpose -.IP \[bu] 2 -required: Whether this parameter must be provided -.IP \[bu] 2 -default (optional): The default value if not specified -.SH CONFIGURATION OPTIONS -.SS workspace (required) -Directory for writing plugin artifacts. -The value is inherited from complyctl and cannot be modified. -.SS profile (required) -The OpenSCAP profile to run for assessment. -The value is inherited from complyctl and cannot be modified. -.SS datastream (optional) -The OpenSCAP datastream to use. -If not set, the plugin will try to determine it based on system -information. -.SS results (optional, default: results.xml) -The name of the generated results file. -.SS arf (optional, default: arf.xml) -The name of the generated ARF file. -.SS policy (optional, default: tailoring_policy.xml) -The name of the generated tailoring file. -.SH EXAMPLES -This is an example of a manifest including all information. -.IP -.EX -{ - \[dq]metadata\[dq]: { - \[dq]id\[dq]: \[dq]openscap\[dq], - \[dq]description\[dq]: \[dq]My openscap plugin\[dq], - \[dq]version\[dq]: \[dq]0.0.1\[dq], - \[dq]types\[dq]: [ - \[dq]pvp\[dq] - ] - }, - \[dq]executablePath\[dq]: \[dq]openscap\-plugin\[dq], - \[dq]sha256\[dq]: \[dq]17e8d0b82c9bfbe7c195505090954488175005898fc0e8da0812c112c582426c\[dq], - \[dq]configuration\[dq]: [ - { - \[dq]name\[dq]: \[dq]workspace\[dq], - \[dq]description\[dq]: \[dq]Directory for writing plugin artifacts\[dq], - \[dq]required\[dq]: true - }, - { - \[dq]name\[dq]: \[dq]profile\[dq], - \[dq]description\[dq]: \[dq]The OpenSCAP profile to run for assessment\[dq], - \[dq]required\[dq]: true - }, - { - \[dq]name\[dq]: \[dq]datastream\[dq], - \[dq]description\[dq]: \[dq]The OpenSCAP datastream to use. If not set, the plugin will try to determine it based on system information\[dq], - \[dq]required\[dq]: false - }, - { - \[dq]name\[dq]: \[dq]policy\[dq], - \[dq]description\[dq]: \[dq]The name of the generated tailoring file\[dq], - \[dq]default\[dq]: \[dq]tailoring_policy.xml\[dq], - \[dq]required\[dq]: false - }, - { - \[dq]name\[dq]: \[dq]arf\[dq], - \[dq]description\[dq]: \[dq]The name of the generated ARF file\[dq], - \[dq]default\[dq]: \[dq]arf.xml\[dq], - \[dq]required\[dq]: false - }, - { - \[dq]name\[dq]: \[dq]results\[dq], - \[dq]description\[dq]: \[dq]The name of the generated results file\[dq], - \[dq]default\[dq]: \[dq]results.xml\[dq], - \[dq]required\[dq]: false - } - ] -} -.EE -.PP -This is an example of a drop\-in file modifying the openscap files. -.IP -.EX -{ - \[dq]configuration\[dq]: [ - { - \[dq]name\[dq]: \[dq]policy\[dq], - \[dq]default\[dq]: \[dq]custom_tailoring_policy.xml\[dq], - }, - { - \[dq]name\[dq]: \[dq]arf\[dq], - \[dq]default\[dq]: \[dq]custom_arf.xml\[dq], - }, - { - \[dq]name\[dq]: \[dq]results\[dq], - \[dq]default\[dq]: \[dq]custom_results.xml\[dq], - } - ] -} -.EE -.SH SEE ALSO -complyctl(1), complyctl\-openscap\-plugin(7) -.PP -See the Upstream project at https://github.com/complytime/complyctl for -more detailed documentation. -.SH AUTHORS -Marcus Burghardt \c -.MT maburgha@redhat.com -.ME \c. diff --git a/docs/man/c2p-openscap-manifest.md b/docs/man/c2p-openscap-manifest.md deleted file mode 100644 index aed38235..00000000 --- a/docs/man/c2p-openscap-manifest.md +++ /dev/null @@ -1,171 +0,0 @@ -% C2P-OPENSCAP-MANIFEST.JSON(5) complyctl OpenSCAP Provider Configuration -% Marcus Burghardt -% June 2025 - -# NAME - -c2p-openscap-manifest.json - Configuration file for the OpenSCAP provider used by complyctl - -# DESCRIPTION - -This file defines the metadata and runtime configuration options for the `openscap-provider`, a provider to be used with `complyctl`. - -It is a JSON-formatted file typically installed at: - -**/usr/share/complyctl/providers/c2p-openscap-manifest.json** - -Some configuration options used by `openscap-provider` can be overridden by using a drop-in file with the same name in "`/etc/complyctl/config.d/`": - -**/etc/complyctl/config.d/c2p-openscap-manifest.json** - -The easiest way to create a drop-in file is copying **/usr/share/complyctl/providers/c2p-openscap-manifest.json** and defining the `default` values. Any other content can be removed to keep the drop-in file clean. See **CONFIGURATION OPTIONS** and **EXAMPLES** sections for more details. - -For some specific cases, it is also possible to inform a custom configuration directory to override `/etc/complyctl/config.d`. -For example, the following command will try to locate and read custom settings from manifest files hosted in `/tmp/providers-conf` instead of `/etc/complyctl/config.d`: - -`complyctl generate --provider-config /tmp/providers-conf` - -See complyctl(1) for more details about the available options. - -# FILE FORMAT - -The configuration is a single JSON object with the following top-level keys: - -- `metadata`: General provider information -- `executablePath`: Name or path of the provider binary -- `sha256`: The checksum of the binary (used for integrity checks) -- `configuration`: An array of runtime configuration options - -# FIELDS - -## metadata - -```json -{ - "id": "openscap", - "description": "My openscap provider", - "version": "0.0.1", - "types": [ "pvp" ] -} -``` - -## executablePath - -Path or name of the provider binary to execute. Typically just: - -```json -"executablePath": "openscap-provider" -``` - -## sha256 -SHA256 checksum of the provider binary, used for runtime verification. - -## configuration -A list of supported configuration parameters for the provider. - -Each entry includes: - -- name: The name of the parameter -- description: Explanation of its purpose -- required: Whether this parameter must be provided -- default (optional): The default value if not specified - -# CONFIGURATION OPTIONS - -## workspace (required) -Directory for writing provider artifacts. The value is inherited from complyctl and cannot be modified. - -## profile (required) -The OpenSCAP profile to run for assessment. The value is inherited from complyctl and cannot be modified. - -## datastream (optional) -The OpenSCAP datastream to use. If not set, the provider will try to determine it based on system information. - -## results (optional, default: results.xml) -The name of the generated results file. - -## arf (optional, default: arf.xml) -The name of the generated ARF file. - -## policy (optional, default: tailoring_policy.xml) -The name of the generated tailoring file. - -# EXAMPLES - -This is an example of a manifest including all information. - -```json -{ - "metadata": { - "id": "openscap", - "description": "My openscap provider", - "version": "0.0.1", - "types": [ - "pvp" - ] - }, - "executablePath": "openscap-provider", - "sha256": "17e8d0b82c9bfbe7c195505090954488175005898fc0e8da0812c112c582426c", - "configuration": [ - { - "name": "workspace", - "description": "Directory for writing provider artifacts", - "required": true - }, - { - "name": "profile", - "description": "The OpenSCAP profile to run for assessment", - "required": true - }, - { - "name": "datastream", - "description": "The OpenSCAP datastream to use. If not set, the provider will try to determine it based on system information", - "required": false - }, - { - "name": "policy", - "description": "The name of the generated tailoring file", - "default": "tailoring_policy.xml", - "required": false - }, - { - "name": "arf", - "description": "The name of the generated ARF file", - "default": "arf.xml", - "required": false - }, - { - "name": "results", - "description": "The name of the generated results file", - "default": "results.xml", - "required": false - } - ] -} -``` - -This is an example of a drop-in file modifying the openscap files. -```json -{ - "configuration": [ - { - "name": "policy", - "default": "custom_tailoring_policy.xml", - }, - { - "name": "arf", - "default": "custom_arf.xml", - }, - { - "name": "results", - "default": "custom_results.xml", - } - ] -} -``` - -# SEE ALSO - -complyctl(1), complyctl-openscap-provider(7) - -See the Upstream project at https://github.com/complytime/complyctl for more detailed documentation. diff --git a/docs/man/complyctl.1 b/docs/man/complyctl.1 index 700fe542..9436e6b3 100644 --- a/docs/man/complyctl.1 +++ b/docs/man/complyctl.1 @@ -1,42 +1,44 @@ -.\" Automatically generated by Pandoc 3.1.11.1 +.\" Automatically generated by Pandoc 3.6.4 .\" -.TH "COMPLYCTL" "1" "April 2025" "Complyctl Manual" "" +.TH "COMPLYCTL" "1" "April 2025" "Complyctl Manual" .SH NAME complyctl \- Complyctl CLI perform compliance assessment activities -using plugins for different underlying technologies. +using providers for different underlying technologies. .SH SYNOPSIS \f[B]complyctl\f[R] [command] [flags] .SH DESCRIPTION Complyctl CLI leverages OSCAL to perform compliance assessment -activities, using plugins for each stage of the lifecycle. +activities, using providers for each stage of the lifecycle. .PP Complyctl can be extended to support desired policy engines (PVPs) by -the use of plugins. -The plugin acts as the integration between complyctl and the PVPs native -interface. -Each plugin is responsible for converting the policy content described +the use of providers. +The provider acts as the integration between complyctl and the PVPs +native interface. +Each provider is responsible for converting the policy content described in OSCAL into the input format expected by the PVP. -In addition, the plugin converts the raw results provided by the PVP +In addition, the provider converts the raw results provided by the PVP into the schema used by complyctl to generate OSCAL output. .PP -Plugins communicate with complyctl via gRPC and can be authored using +Providers communicate with complyctl via gRPC and can be authored using any preferred language. -The plugin acts as the gRPC server while the complyctl CLI acts as the +The provider acts as the gRPC server while the complyctl CLI acts as the client. When a complyctl command is run, it invokes the appropriate method -served by the plugin. +served by the provider. .PP -See more about authoring plugins at -https://github.com/complytime/complyctl/blob/main/docs/PLUGIN_GUIDE.md. +See more about authoring providers at +https://github.com/complytime/complytime\-providers/blob/main/docs/provider\-guide.md. .PP -Review the \f[CR]openscap\-plugin\f[R] that is shipped with complyctl at -https://github.com/complytime/complyctl/tree/main/cmd/openscap\-plugin/README.md. +Review the openscap\-provider that is shipped with complytime\-providers +at +https://github.com/complytime/complytime\-providers/tree/main/cmd/openscap\-provider/README.md. .PP -Also check the \[lq]SEE ALSO\[rq] section for plugin specific man pages. +Also check the complytime\-providers repository for provider\-specific +documentation. .PP Complyctl is built on https://github.com/oscal\-compass/compliance\-to\-policy\-go which -provides a flexible plugin framework for leveraging OSCAL with various +provides a flexible provider framework for leveraging OSCAL with various PVPs. .SH COMMANDS \f[B]completion\f[R] Generate the autocompletion script for the @@ -72,16 +74,16 @@ about controls, rules, and parameters within a framework. .IP .EX $ complyctl info anssi_bp28_minimal -# List the controls in the framework +\f[I]# List the controls in the framework\f[R] $ complyctl info anssi_bp28_minimal \-\-control -# List details about a control and rules used by that control +\f[I]# List details about a control and rules used by that control\f[R] $ complyctl info anssi_bp28_minimal \-\-rule -# List the parameters used be a specific rule +\f[I]# List the parameters used be a specific rule\f[R] $ complyctl info anssi_bp28_minimal \-\-parameter -# See the current set value and valid alternatives for a parameter +\f[I]# See the current set value and valid alternatives for a parameter\f[R] .EE .SS Assessment Scoping using the plan command The \f[CR]plan\f[R] command is used for scoping an OSCAL Assessment @@ -93,10 +95,10 @@ controls, rules, and parameters. .IP .EX $ complyctl plan anssi_bp28_minimal \-\-dry\-run \-\-out config.yml -# Populate framework\-id defaults in config.yml +\f[I]# Populate framework\-id defaults in config.yml\f[R] $ complyctl plan anssi_bp28_minimal \-\-scope\-config config.yml -# Configure plan based on updates made in config.yml +\f[I]# Configure plan based on updates made in config.yml\f[R] .EE .SS Configuring the Assessment Plan .SS Excluding Controls and Rules @@ -137,32 +139,32 @@ The controlId \f[CR]r31\f[R] has a valid parameter update to \f[CR]var_password_pam_ucredit\f[R] from \[lq]1\[rq] to \[lq]365.\[rq] .IP .EX -frameworkId: anssi_bp28_minimal -includeControls: -#\- controlId: r30 # Delete all fields associated with r30 -# controlTitle: Removal Of Unused User Accounts -# includeRules: -# \- \[dq]*\[dq] -# selectParameters: -# \- name: N/A -# value: N/A -\- controlId: r31 - controlTitle: User Password Strength - includeRules: - \- \[dq]*\[dq] - excludeRules: # Use to exclude a rule specific to the controlId - \- \[dq]accounts_password_set_max_life_root\[dq] - waiveRules: # Use to waive a rule specific to the controlId - \- \[dq]accounts_password_pam_minlen\[dq] - selectParameters: - \- name: var_password_pam_ucredit # Initial value = \[dq]1\[dq] - value: \[dq]365\[dq] # Update parameter value to a valid alternative (\[dq]365\[dq]) - \- name: var_password_pam_unix_rounds - value: \[dq]11\[dq] # Initial value = \[dq]11\[dq] -globalExcludeRules: -\- \[dq]*\[dq] # This will exclude all rules for all controlIds -globalWaiveRules: -\- \[dq]*\[dq] # This will waive all rules for all controlIds +frameworkId\f[B]:\f[R] anssi_bp28_minimal +includeControls\f[B]:\f[R] +\f[I]#\- controlId: r30 # Delete all fields associated with r30\f[R] +\f[I]# controlTitle: Removal Of Unused User Accounts\f[R] +\f[I]# includeRules:\f[R] +\f[I]# \- \[dq]*\[dq]\f[R] +\f[I]# selectParameters:\f[R] +\f[I]# \- name: N/A\f[R] +\f[I]# value: N/A\f[R] +\f[B]\-\f[R] controlId\f[B]:\f[R] r31 + controlTitle\f[B]:\f[R] User Password Strength + includeRules\f[B]:\f[R] + \f[B]\-\f[R] \[dq]*\[dq] + excludeRules\f[B]:\f[R]\f[I] # Use to exclude a rule specific to the controlId\f[R] + \f[B]\-\f[R] \[dq]accounts_password_set_max_life_root\[dq] + waiveRules\f[B]:\f[R]\f[I] # Use to waive a rule specific to the controlId\f[R] + \f[B]\-\f[R] \[dq]accounts_password_pam_minlen\[dq] + selectParameters\f[B]:\f[R] + \f[B]\-\f[R] name\f[B]:\f[R] var_password_pam_ucredit\f[I] # Initial value = \[dq]1\[dq]\f[R] + value\f[B]:\f[R] \[dq]365\[dq]\f[I] # Update parameter value to a valid alternative (\[dq]365\[dq])\f[R] + \f[B]\-\f[R] name\f[B]:\f[R] var_password_pam_unix_rounds + value\f[B]:\f[R] \[dq]11\[dq]\f[I] # Initial value = \[dq]11\[dq]\f[R] +globalExcludeRules\f[B]:\f[R] +\f[B]\-\f[R] \[dq]*\[dq]\f[I] # This will exclude all rules for all controlIds\f[R] +globalWaiveRules\f[B]:\f[R] +\f[B]\-\f[R] \[dq]*\[dq]\f[I] # This will waive all rules for all controlIds\f[R] .EE .SS Assessment Plan Scope Inheritance When excluding a \f[CR]controlId\f[R] from the \f[CR]config.yml\f[R], @@ -204,7 +206,7 @@ After configuring the \f[CR]assessment\-plan.json\f[R] the activities of the assessment plan and their selected parameter values will be updated. .SS Generating Policy Artifacts from the Assessment Plan The complyctl \f[CR]generate\f[R] command will generate the -\f[B]plugin\-specific\f[R] policy from the OSCAL Assessment Plan, more +\f[B]provider\-specific\f[R] policy from the OSCAL Assessment Plan, more specifically it processes the validation component from the assessment\-plan.json. .SS Scanning System Environment with the Assessment Plan and Policy Artifacts @@ -217,11 +219,13 @@ Assessment Results will be generated in the \f[CR]assessment\-results.json\f[R] file and can be viewed as Markdown by passing the \f[CR]\-\-with\-md\f[R] flag. .SH SEE ALSO -complyctl\-openscap\-plugin(7) -.PP -See the Upstream project at https://github.com/complytime/complyctl for +See the upstream project at https://github.com/complytime/complyctl for more detailed documentation. .PP +See the complytime\-providers repository at +https://github.com/complytime/complytime\-providers for +provider\-specific documentation. +.PP See https://github.com/oscal\-compass/compliance\-to\-policy\-go project. .SH COPYRIGHT diff --git a/docs/man/complyctl.md b/docs/man/complyctl.md index 4b426694..2aab2d10 100644 --- a/docs/man/complyctl.md +++ b/docs/man/complyctl.md @@ -23,9 +23,9 @@ Providers communicate with complyctl via gRPC and can be authored using any pref See more about authoring providers at https://github.com/complytime/complytime-providers/blob/main/docs/provider-guide.md. -Review the `openscap-provider that is shipped with complytime-providers at https://github.com/complytime/complytime/complytime-providers/tree/main/cmd/openscap-provider/README.md. +Review the openscap-provider that is shipped with complytime-providers at https://github.com/complytime/complytime-providers/tree/main/cmd/openscap-provider/README.md. -Also check the "SEE ALSO" section for provider specific man pages. +Also check the complytime-providers repository for provider-specific documentation. Complyctl is built on https://github.com/oscal-compass/compliance-to-policy-go which provides a flexible provider framework for leveraging OSCAL with various PVPs. @@ -168,9 +168,9 @@ Assessment Results will be generated in the `assessment-results.json` file and c # SEE ALSO -complyctl-openscap-provider(7) +See the upstream project at https://github.com/complytime/complyctl for more detailed documentation. -See the Upstream project at https://github.com/complytime/complyctl for more detailed documentation. +See the complytime-providers repository at https://github.com/complytime/complytime-providers for provider-specific documentation. See https://github.com/oscal-compass/compliance-to-policy-go project. diff --git a/specs/004-providers-repository-split/tasks.md b/specs/004-providers-repository-split/tasks.md index 4c9e1176..ca613c37 100644 --- a/specs/004-providers-repository-split/tasks.md +++ b/specs/004-providers-repository-split/tasks.md @@ -101,7 +101,7 @@ directive. **Purpose**: Vendor dependencies in `complytime-providers` and prepare CI for publishing release artifacts. - [x] T037 [US2] Run `go mod vendor` in `complytime-providers/` to create the `vendor/` tree -- [ ] T038 [US2] Remove `replace` directive from `complytime-providers/go.mod`; update `require github.com/complytime/complyctl` to the tagged release version from Phase 1 checkpoint; re-run `go mod vendor` +- [x] T038 [US2] Remove `replace` directive from `complytime-providers/go.mod`; update `require github.com/complytime/complyctl` to the tagged release version from Phase 1 checkpoint; re-run `go mod vendor` - [x] T039 [US2] Create `.github/workflows/ci.yml` in `complytime-providers/` with jobs: build both providers, run tests, and publish release artifacts (`complyctl-provider-openscap` and `complyctl-provider-ampel`) on tag push - [x] T040 [US1][US3] Verify `make build` in `complytime-providers/` produces both `complyctl-provider-openscap` and `complyctl-provider-ampel` binaries with no local complyctl source tree present @@ -129,10 +129,10 @@ to download provider binary from `complytime-providers` release artifact. - [x] T048 [US4] Confirm `SC-002`: full-text search of complyctl for "plugin" (case-insensitive) in Go sources, Makefile, CI workflows, and docs returns zero provider-concept matches (library name `hashicorp/go-plugin` and proto package `complyctl.plugin.v1` are exempt) - [x] T049 [US2] Confirm `SC-003`: both providers build from `complytime-providers` without a local complyctl source tree - [x] T050 [US1] Confirm `SC-004`: all complyctl unit tests pass (`go test ./...`) -- [ ] T051 [US3] Confirm `SC-005`: complyctl E2E tests pass using a provider binary built from `complytime-providers` -- [ ] T052 [US3] Confirm `SC-006`: a binary built from `complytime-providers` is discovered and invoked by `complyctl scan` correctly (binary name and discovery paths unchanged) +- [x] T051 [US3] Confirm `SC-005`: complyctl E2E tests pass using a provider binary built from `complytime-providers` +- [x] T052 [US3] Confirm `SC-006`: a binary built from `complytime-providers` is discovered and invoked by `complyctl scan` correctly (binary name and discovery paths unchanged) - [x] T053 [US1] Confirm `SC-007`: `make build` in complyctl produces only the `complyctl` CLI binary -- [ ] T054 [US1] Confirm `SC-008`: complyctl CI pipeline passes without modification to any step that previously built or tested provider source directories +- [x] T054 [US1] Confirm `SC-008`: complyctl CI pipeline passes without modification to any step that previously built or tested provider source directories --- diff --git a/specs/005-rpm-packaging-ci/checklists/requirements.md b/specs/005-rpm-packaging-ci/checklists/requirements.md new file mode 100644 index 00000000..c3850d52 --- /dev/null +++ b/specs/005-rpm-packaging-ci/checklists/requirements.md @@ -0,0 +1,37 @@ +# Specification Quality Checklist: RPM Packaging and CI for Split Repositories + +**Purpose**: Validate specification completeness and quality before proceeding to planning +**Created**: 2026-04-24 +**Feature**: [spec.md](../spec.md) + +## Content Quality + +- [x] No implementation details (languages, frameworks, APIs) +- [x] Focused on user value and business needs +- [x] Written for non-technical stakeholders +- [x] All mandatory sections completed + +## Requirement Completeness + +- [x] No [NEEDS CLARIFICATION] markers remain +- [x] Requirements are testable and unambiguous +- [x] Success criteria are measurable +- [x] Success criteria are technology-agnostic (no implementation details) +- [x] All acceptance scenarios are defined +- [x] Edge cases are identified +- [x] Scope is clearly bounded +- [x] Dependencies and assumptions identified + +## Feature Readiness + +- [x] All functional requirements have clear acceptance criteria +- [x] User scenarios cover primary flows +- [x] Feature meets measurable outcomes defined in Success Criteria +- [x] No implementation details leak into specification + +## Notes + +- All items pass validation. Specification is ready for `/speckit.plan`. +- The spec references Fedora Packaging Guidelines and Go RPM macros as domain concepts (packaging standards), not as implementation choices -- these are the mandated distribution channel requirements. +- RPM spec file structure and Packit configuration are packaging artifacts, not implementation details -- they are the deliverables themselves. +- Integration tests between complyctl and complytime-providers are explicitly deferred (FR-023). diff --git a/specs/005-rpm-packaging-ci/contracts/packaging-interface.md b/specs/005-rpm-packaging-ci/contracts/packaging-interface.md new file mode 100644 index 00000000..903ec9e7 --- /dev/null +++ b/specs/005-rpm-packaging-ci/contracts/packaging-interface.md @@ -0,0 +1,79 @@ +# Packaging Interface Contract + +**Feature**: [../spec.md](../spec.md) | **Plan**: [../plan.md](../plan.md) +**Date**: 2026-04-24 + +## Package Ownership Contract + +The `complyctl` RPM **owns** the provider directory tree: + +- `/usr/libexec/complytime/` (directory) +- `/usr/libexec/complytime/providers/` (directory) + +Provider sub-packages install files **into** this directory without owning it. +This ensures `complyctl` must be installed first, which is enforced by the +`Requires: complyctl >= X.Y.Z` dependency on each provider sub-package. + +If the `complyctl` RPM is removed, `dnf` will also remove provider packages +(they depend on it). The provider directories are cleaned up with the +complyctl package removal. + +## Binary Naming Convention + +Provider binaries MUST follow the pattern `complyctl-provider-`. This is +how the `complyctl` discovery mechanism finds providers at runtime. + +The convention is defined in +`internal/complytime/consts.go:ProviderExecutablePrefix = "complyctl-provider-"`. + +The discovery searches two locations: +1. `~/.complytime/providers/` (user-local) +2. `/usr/libexec/complytime/providers/` (system-wide, RPM install path) + +## Version Compatibility + +Provider sub-packages declare `Requires: complyctl >= X.Y.Z` where `X.Y.Z` is +the first complyctl release containing the `pkg/provider/` SDK (renamed from +`pkg/plugin/` in spec 004). + +This ensures: +- Users cannot install providers against a complyctl version that predates the + provider SDK rename (which would be incompatible). +- Newer complyctl versions remain compatible (the minimum version constraint + does not prevent upgrades). +- The exact version is determined at implementation time when the post-spec-004 + release is tagged. + +## Packit Configuration Contract + +Both repositories use identical Packit job structure: + +| Job | Trigger | Purpose | +|----------------------|---------------|--------------------------------------------| +| `copr_build` | pull_request | Build RPMs from PR source in COPR | +| `tests` | pull_request | Run TMT tests via Testing Farm | +| `propose_downstream` | release | Create dist-git PRs for Fedora branches | +| `koji_build` | commit | Submit Koji builds after dist-git merge | +| `bodhi_update` | commit | Create Bodhi updates for released versions | + +The `tests` job depends on `copr_build` completing first. Built packages are +automatically installed in the testing environment by Testing Farm. + +## TMT Test Contract + +### complyctl tests (`plans/test-RPM-provide-content.fmf`) + +Validates: +- `complyctl version` exits with code 0 +- `complyctl --help` exits with code 0 + +### complytime-providers tests (`plans/test-RPM-providers.fmf`) + +Validates: +- `complyctl-provider-openscap` binary exists at expected path +- `complyctl-provider-ampel` binary exists at expected path +- Both binaries have executable permissions + +Provider binaries are gRPC servers and cannot be invoked standalone for +functional testing. File presence and permissions are the appropriate smoke +test level. Integration testing is deferred. diff --git a/specs/005-rpm-packaging-ci/data-model.md b/specs/005-rpm-packaging-ci/data-model.md new file mode 100644 index 00000000..e6172baa --- /dev/null +++ b/specs/005-rpm-packaging-ci/data-model.md @@ -0,0 +1,113 @@ +# Data Model: RPM Packaging and CI for Split Repositories + +**Feature**: [spec.md](spec.md) | **Plan**: [plan.md](plan.md) +**Date**: 2026-04-24 + +## RPM Package Entities + +### complyctl (source RPM → binary RPM) + +```text +complyctl (source RPM) +└── complyctl (binary RPM) + ├── /usr/bin/complyctl # CLI binary + ├── /usr/share/man/man1/complyctl.1.gz # Man page + ├── /usr/share/licenses/complyctl/LICENSE # License + ├── /usr/share/licenses/complyctl/modules.txt # Auto-generates bundled provides + ├── /usr/libexec/complytime/ # Owned directory + └── /usr/libexec/complytime/providers/ # Owned directory (providers install here) +``` + +- **Source**: `github.com/complytime/complyctl` +- **Module path**: `github.com/complytime/complyctl` +- **Build target**: `./cmd/complyctl/` +- **Version injection**: 4 linker flags into `internal/version.*` +- **Dependency direction**: None (standalone, no provider requirements) + +### complytime-providers (source RPM → two sub-packages) + +```text +complytime-providers (source RPM) +├── complytime-providers-openscap (binary sub-package) +│ ├── /usr/libexec/complytime/providers/complyctl-provider-openscap +│ └── /usr/share/licenses/complytime-providers-openscap/LICENSE +│ Requires: complyctl >= X.Y.Z +│ Requires: scap-security-guide +│ +└── complytime-providers-ampel (binary sub-package) + ├── /usr/libexec/complytime/providers/complyctl-provider-ampel + └── /usr/share/licenses/complytime-providers-ampel/LICENSE + Requires: complyctl >= X.Y.Z +``` + +- **Source**: `github.com/complytime/complytime-providers` +- **Module path**: `github.com/complytime/complytime-providers` +- **Build targets**: `./cmd/openscap-provider/` and `./cmd/ampel-provider/` +- **No main binary RPM** is produced (no `%files` for main package) +- **No version injection** (RPM version suffices for providers) + +## Dependency Graph + +```text + ┌──────────────────────────────────────┐ + │ complytime-providers-openscap │ + │ (complyctl-provider-openscap binary) │ + └──────────┬──────────┬────────────────┘ + │ │ + Requires >= │ │ Requires + │ │ + ┌──────────▼──┐ ┌───▼──────────────────┐ + │ complyctl │ │ scap-security-guide │ + │ (CLI binary)│ │ (SCAP content) │ + └──────────▲──┘ └────────────────────────┘ + │ + Requires >= │ + │ + ┌──────────┴──────────────────────────┐ + │ complytime-providers-ampel │ + │ (complyctl-provider-ampel binary) │ + └──────────────────────────────────────┘ +``` + +## Directory Ownership + +| Path | Owned By | Notes | +|---------------------------------------|----------------|-----------------------------------| +| `/usr/bin/complyctl` | complyctl | CLI entry point | +| `/usr/share/man/man1/complyctl.1.gz` | complyctl | Man page | +| `/usr/libexec/complytime/` | complyctl | Parent directory | +| `/usr/libexec/complytime/providers/` | complyctl | Provider discovery directory | +| `.../providers/complyctl-provider-openscap` | complytime-providers-openscap | Installed into complyctl-owned dir | +| `.../providers/complyctl-provider-ampel` | complytime-providers-ampel | Installed into complyctl-owned dir | + +## Packit Pipeline Stages + +```text +┌─ Per-PR Pipeline ─────────────────────────────────────────────────────┐ +│ │ +│ PR opened → copr_build → tests (Testing Farm/TMT) → PR status check │ +│ │ +└───────────────────────────────────────────────────────────────────────┘ + +┌─ Release Pipeline ────────────────────────────────────────────────────┐ +│ │ +│ Git tag → GoReleaser → GitHub Release │ +│ └─► Packit propose_downstream → dist-git PR │ +│ └─► (merge) → koji_build → bodhi_update │ +│ │ +└───────────────────────────────────────────────────────────────────────┘ +``` + +Both pipelines run independently for each repository. The complyctl pipeline +produces a single binary RPM. The complytime-providers pipeline produces two +sub-package RPMs. + +## CI Target Matrix + +| Target | COPR Build | Testing Farm | Propose Downstream | Koji Build | Bodhi Update | +|---------------------------|:---:|:---:|:---:|:---:|:---:| +| fedora-rawhide-x86_64 | PR | PR | release | commit | -- | +| fedora-43-x86_64 | PR | PR | release | commit | commit | +| fedora-42-x86_64 | PR | PR | release | commit | commit | +| centos-stream-10-x86_64 | PR | PR | -- | -- | -- | +| centos-stream-9-x86_64 | PR | PR | -- | -- | -- | diff --git a/specs/005-rpm-packaging-ci/plan.md b/specs/005-rpm-packaging-ci/plan.md new file mode 100644 index 00000000..667e8b69 --- /dev/null +++ b/specs/005-rpm-packaging-ci/plan.md @@ -0,0 +1,114 @@ +# Implementation Plan: RPM Packaging and CI for Split Repositories + +**Branch**: `005-rpm-packaging-ci` | **Date**: 2026-04-24 | **Spec**: [spec.md](spec.md) +**Input**: Feature specification from `/specs/005-rpm-packaging-ci/spec.md` + +## Summary + +Restore Fedora RPM packaging for complyctl and create new packaging for +complytime-providers after the repository split (spec 004). The complyctl spec +is simplified to deliver only the CLI binary and man page. A new spec is created +in complytime-providers producing two sub-packages (openscap and ampel +providers) with no main binary RPM. Both repositories get Packit CI/CD +automation and TMT smoke tests. Release process documentation and GoReleaser +configuration are updated to reflect the new packaging structure. + +## Technical Context + +**Language/Version**: Go 1.25 +**Primary Dependencies**: go-rpm-macros, Packit, Testing Farm (TMT/FMF) +**Storage**: N/A +**Testing**: `go test` (unit, in `%check`), TMT inline scripts (RPM smoke) +**Target Platform**: Fedora rawhide/43/42, CentOS Stream 9/10 (x86_64) +**Project Type**: CLI + provider binaries (RPM packaging) +**Performance Goals**: N/A +**Constraints**: Fedora Packaging Guidelines for Go projects +**Scale/Scope**: 2 repositories, 3 binary RPMs, release automation for both + +## Constitution Check + +*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* + +| Principle | Status | Notes | +|------------------------------------|--------|---------------------------------------------------------------------------| +| I. Single Source of Truth | PASS | Provider path centralized via `%global app_dir`; reused across both specs | +| II. Simplicity & Isolation | PASS | Each spec has one concern; TMT plans are minimal smoke tests | +| III. Incremental Improvement | PASS | Packaging-only; integration tests deferred to separate spec | +| IV. Readability First | PASS | Specs follow established Fedora patterns with clear comments | +| V. Do Not Reinvent the Wheel | PASS | Standard Go RPM macros, Packit, TMT -- all established Fedora tools | +| VI. Composability | PASS | Independent RPM packages compose via standard `Requires` dependency | +| VII. Convention Over Configuration | PASS | Follows Fedora Go packaging conventions; Packit with standard job configs | + +No violations detected. No complexity tracking needed. + +## Project Structure + +### Documentation (this feature) + +```text +specs/005-rpm-packaging-ci/ +├── plan.md # This file +├── research.md # Phase 0 output +├── data-model.md # Phase 1 output +├── quickstart.md # Phase 1 output +├── contracts/ +│ └── packaging-interface.md # Phase 1 output +└── tasks.md # Phase 2 output (/speckit.tasks) +``` + +### Source Code (both repositories) + +```text +# complyctl repository (this repo) -- files to UPDATE +complyctl.spec # UPDATE: remove provider sub-package, add man page +.goreleaser.yaml # UPDATE: remove openscap-plugin build entry +.packit.yaml # KEEP: already correct +.fmf/version # EXISTS: FMF metadata root +plans/ + test-RPM-provide-content.fmf # KEEP: existing smoke test +docs/ + man/complyctl.md # UPDATE: plugin→provider terminology + man/complyctl.1 # REGENERATE: via make man + RELEASE_PROCESS.md # UPDATE: reflect split packaging structure + TESTING_FARM.md # KEEP: generic, no provider-specific refs + INSTALLATION.md # KEEP: no provider-specific refs + +# complytime-providers repository (github.com/complytime/complytime-providers) +complytime-providers.spec # NEW: source RPM → two sub-packages only +.packit.yaml # NEW: full Packit CI/CD config +.fmf/ + version # NEW: FMF metadata root (contains "1") +plans/ + test-RPM-providers.fmf # NEW: provider binary presence + permissions +``` + +**Structure Decision**: This feature modifies packaging and CI configuration +files in two repositories. No application source code changes are required. +The complyctl repo changes are in-tree; the complytime-providers changes require +work in the external repository at `github.com/complytime/complytime-providers`. + +## Key Research Decisions + +Full details in [research.md](research.md). + +1. **Bundled provides**: Automatic generation via `vendor/modules.txt` installed + as `%license`; no manual `Provides: bundled(golang(...))` list needed. + +2. **Build scope**: complyctl spec changes from `go build ./cmd/...` to + `go build ./cmd/complyctl/` (avoids building dev-only binaries in RPM). + +3. **No main package**: complytime-providers source RPM omits `%files` for the + main package name; only sub-packages are produced. + +4. **TMT format**: Inline `execute.script` in `.fmf` files (matches existing + complyctl pattern). + +5. **Man page**: Install pre-built `docs/man/complyctl.1` from source tarball; + no pandoc BuildRequires. Source `complyctl.md` updated for terminology, then + regenerated via `make man` before release. + +6. **GoReleaser**: Remove `openscap-plugin` build entry from `.goreleaser.yaml` + (tracked by spec 004 FR-010, prerequisite for release automation). + +7. **Release docs**: Update `RELEASE_PROCESS.md` to reflect that providers are + a separate Fedora package with independent release and Packit automation. diff --git a/specs/005-rpm-packaging-ci/quickstart.md b/specs/005-rpm-packaging-ci/quickstart.md new file mode 100644 index 00000000..ed2ed114 --- /dev/null +++ b/specs/005-rpm-packaging-ci/quickstart.md @@ -0,0 +1,142 @@ +# Quickstart: RPM Packaging and CI for Split Repositories + +**Feature**: [spec.md](spec.md) | **Plan**: [plan.md](plan.md) +**Date**: 2026-04-24 + +## Prerequisites + +```bash +# Fedora packaging tools +sudo dnf install rpm-build mock golang go-rpm-macros + +# TMT tools (optional, for local test plan validation) +sudo dnf install tmt + +# Ensure mock group membership +sudo usermod -a -G mock $USER +``` + +## Testing complyctl RPM Locally + +### Quick spec lint + +```bash +rpmlint complyctl.spec +``` + +### Build with mock (Fedora rawhide) + +```bash +# Download source tarball +spectool -g -R complyctl.spec + +# Build SRPM +rpmbuild -bs complyctl.spec \ + --define "_sourcedir $(pwd)" \ + --define "_srcrpmdir $(pwd)" + +# Build in mock +mock -r fedora-rawhide-x86_64 rebuild complyctl-*.src.rpm +``` + +### Verify the built RPM + +```bash +# List files in the RPM +rpm -qlp /var/lib/mock/fedora-rawhide-x86_64/result/complyctl-*.x86_64.rpm + +# Verify no provider binaries are included +rpm -qlp /var/lib/mock/fedora-rawhide-x86_64/result/complyctl-*.x86_64.rpm \ + | grep -v debuginfo | grep provider && echo "FAIL: provider found" || echo "OK" + +# Verify man page is included +rpm -qlp /var/lib/mock/fedora-rawhide-x86_64/result/complyctl-*.x86_64.rpm \ + | grep complyctl.1 && echo "OK: man page found" || echo "FAIL: missing man page" + +# Verify bundled provides are generated +rpm -qp --provides /var/lib/mock/fedora-rawhide-x86_64/result/complyctl-*.x86_64.rpm \ + | grep "bundled(golang" | head -5 +``` + +### Test with Packit locally (alternative) + +```bash +packit build locally +``` + +## Testing complytime-providers RPM Locally + +Run from the `complytime-providers` repository: + +```bash +# Download source tarball +spectool -g -R complytime-providers.spec + +# Build SRPM +rpmbuild -bs complytime-providers.spec \ + --define "_sourcedir $(pwd)" \ + --define "_srcrpmdir $(pwd)" + +# Build in mock +mock -r fedora-rawhide-x86_64 rebuild complytime-providers-*.src.rpm + +# Verify two sub-packages produced (no main package) +ls /var/lib/mock/fedora-rawhide-x86_64/result/*.rpm | grep -v src | grep -v debug + +# Expected output: +# complytime-providers-openscap-*.x86_64.rpm +# complytime-providers-ampel-*.x86_64.rpm +# (no complytime-providers-*.x86_64.rpm without a suffix) + +# Check provider binary paths +rpm -qlp /var/lib/mock/fedora-rawhide-x86_64/result/complytime-providers-openscap-*.x86_64.rpm +rpm -qlp /var/lib/mock/fedora-rawhide-x86_64/result/complytime-providers-ampel-*.x86_64.rpm + +# Verify dependency on complyctl +rpm -qp --requires /var/lib/mock/fedora-rawhide-x86_64/result/complytime-providers-openscap-*.x86_64.rpm \ + | grep complyctl +``` + +## Verifying TMT Plans + +```bash +# Lint TMT plans (from repo root) +tmt lint + +# List discovered plans +tmt plan ls + +# Dry-run tests locally +tmt run --all provision --how local discover --how fmf +``` + +## Verifying Packit Configuration + +```bash +# Validate packit config +packit validate-config + +# Test COPR build locally +packit build locally +``` + +## Verifying GoReleaser Configuration + +```bash +# Check config syntax (does not run a release) +goreleaser check + +# Dry-run build (produces local artifacts without publishing) +goreleaser build --snapshot --clean +``` + +## Man Page Workflow + +```bash +# Update the man page source (docs/man/complyctl.md) +# Then regenerate the man page: +make man + +# Verify the generated man page +man -l docs/man/complyctl.1 +``` diff --git a/specs/005-rpm-packaging-ci/research.md b/specs/005-rpm-packaging-ci/research.md new file mode 100644 index 00000000..ba543835 --- /dev/null +++ b/specs/005-rpm-packaging-ci/research.md @@ -0,0 +1,138 @@ +# Research: RPM Packaging and CI for Split Repositories + +**Feature**: [spec.md](spec.md) | **Plan**: [plan.md](plan.md) +**Date**: 2026-04-24 + +## Decision 1: RPM Spec Macros for Go Projects + +**Decision**: Use `%gometa -f`, `%goprep -k`, manual `go build` with +`%set_build_flags` and `-buildmode=pie`, and `go test -mod=vendor` in `%check`. + +**Rationale**: The existing complyctl.spec already uses this pattern. The `-f` +flag on `%gometa` uses `golang_arches_future` (excludes i686). The `-k` flag on +`%goprep` preserves the `vendor/` directory. Manual `go build` (instead of +`%gobuild`) is needed because complyctl injects custom version info via +`-ldflags -X`. For complytime-providers, manual `go build` is also appropriate +since two separate binaries need specific output names. + +**Alternatives considered**: +- `%gobuild` macro: Wraps `go build` with Fedora hardening flags but does not + easily support custom LD flags or multiple output binaries with specific + names. Would require workarounds. + +## Decision 2: Bundled Dependency Declaration + +**Decision**: Install `vendor/modules.txt` as a `%license` file. The +`go_mod_vendor.prov` RPM generator (part of `go-rpm-macros`) automatically +parses it and emits `Provides: bundled(golang(...)) = ` entries at +build time. + +**Rationale**: Eliminates manual maintenance of a bundled provides list. The +generator auto-produces accurate provides from `vendor/modules.txt`. This is the +recommended modern Fedora approach for Go projects with vendored dependencies. + +**Alternatives considered**: +- Manual `Provides: bundled(golang(...))` lines in the spec: Requires updating + on every dependency change. Error-prone and labor-intensive. +- `gobundled.prov`: Older mechanism for `-devel` subpackages. Not applicable + to binary-only packages. + +## Decision 3: Sub-packages Without Main Package + +**Decision**: Omit the `%files` section for the main `complytime-providers` +package name. RPM produces only the two sub-packages. + +**Rationale**: The source RPM produces two independent provider binaries with +no shared runtime files. A main package would be either empty or a meta-package. +Per clarification session (Option A), no main binary RPM is published. + +**Alternatives considered**: +- Empty meta-package requiring both providers: Rejected (user wants individual + provider installation choice). +- Shared-files package with LICENSE/docs: Rejected (each sub-package includes + its own LICENSE). + +## Decision 4: TMT Test Plan Structure + +**Decision**: Use inline `execute.script` in `.fmf` files for smoke tests. + +**Rationale**: Matches the existing `plans/test-RPM-provide-content.fmf` pattern +in complyctl. Simple enough that separate test script files add no value. +Testing Farm executes the script commands after COPR-built RPMs are installed. + +**Alternatives considered**: +- Separate `tests/` directory with `main.fmf` + shell scripts: Appropriate for + complex test suites but overkill for binary presence and version checks. + +## Decision 5: complyctl Build Scope in RPM + +**Decision**: Change build command from `go build ./cmd/...` to +`go build ./cmd/complyctl/` in the RPM spec. + +**Rationale**: After the split, `cmd/` contains 4 entries: `complyctl`, +`behavioral-report`, `mock-oci-registry`, `test-provider`. Only `complyctl` +should be in the RPM. Building all 4 wastes build time and may cause build +failures if dev-only `cmd/` entries have dependencies not available in the +RPM build root. + +**Alternatives considered**: +- Keep `./cmd/...` and install only `complyctl`: Functional but wasteful and + risks build failures from dev-only dependencies. + +## Decision 6: Man Page Packaging + +**Decision**: Install the pre-built `docs/man/complyctl.1` from the source +tarball. No pandoc BuildRequires needed. + +**Rationale**: The man page source (`complyctl.md`) is maintained by developers +and converted to `complyctl.1` via `make man` (uses pandoc) as part of the +development workflow. The pre-built `.1` file is committed to the repo and +included in the release tarball. The RPM spec simply installs it. This avoids +adding pandoc as a BuildRequires (which may not be available on all build +targets like CentOS Stream). + +**Alternatives considered**: +- Build from source during RPM build: Requires `BuildRequires: pandoc`. Adds + build complexity and a dependency that may not be universally available. + +## Decision 7: Release Process and GoReleaser Updates + +**Decision**: Update `.goreleaser.yaml` to remove the `openscap-plugin` build +entry. Update `docs/RELEASE_PROCESS.md` to reflect the new multi-repository +packaging structure. + +**Rationale**: The `.goreleaser.yaml` currently defines two builds: `complyctl` +(from `./cmd/complyctl/`) and `openscap-plugin` (from `./cmd/openscap-plugin`). +After the repository split, `cmd/openscap-plugin` no longer exists, so the +GoReleaser release will fail. The `RELEASE_PROCESS.md` references the Fedora +package automation but does not mention that providers are now a separate +package. These updates are prerequisites for the Packit release automation to +function correctly. + +The `.goreleaser.yaml` update is tracked by spec 004 FR-010 ("CI workflows MUST +be updated to remove all steps that reference the removed provider source +directories"). It is included in this plan because the release process directly +gates the Packit `propose_downstream` automation that this feature enables. + +**Alternatives considered**: +- Defer to spec 004: The GoReleaser fix is technically in spec 004 scope, but + release automation for this feature cannot be validated without it. Including + it here avoids a circular dependency. + +## Decision 8: Provider Binary Test Approach + +**Decision**: TMT tests for complytime-providers validate file presence at the +expected path and executable permissions. No runtime invocation of provider +binaries. + +**Rationale**: Provider binaries are gRPC servers invoked by complyctl via +the hashicorp/go-plugin protocol. They do not support standalone `--help` or +`--version` flags. Verifying they are installed at the correct location with +correct permissions is the appropriate level for smoke testing. Integration +testing (complyctl invoking providers) is explicitly deferred to a separate +specification. + +**Alternatives considered**: +- Invoke provider binary standalone: Provider binaries are gRPC servers and will + exit with an error when invoked without a parent complyctl process. Not useful + for smoke testing. diff --git a/specs/005-rpm-packaging-ci/spec.md b/specs/005-rpm-packaging-ci/spec.md new file mode 100644 index 00000000..af20ced3 --- /dev/null +++ b/specs/005-rpm-packaging-ci/spec.md @@ -0,0 +1,225 @@ +# Feature Specification: RPM Packaging and CI for Split Repositories + +**Feature Branch**: `005-rpm-packaging-ci` +**Created**: 2026-04-24 +**Status**: Draft +**Input**: User description: "After splitting the repository by moving the openscap and ampel providers to complytime-providers repository, the RPM is naturally broken. The spec file in complyctl will only deliver the complyctl binary. Another single spec file must be created in complytime-providers to generate two sub-packages (OpenSCAP and Ampel providers). Provider RPMs must require complyctl. Testing-farm CI tests for each PR and Packit automation for Fedora Packages on release." + +## Overview + +The repository split (spec 004) moved the OpenSCAP and Ampel providers from complyctl to the `complytime-providers` repository. The current RPM spec (`complyctl.spec`) still references the removed provider directories (`cmd/openscap-plugin/`), breaking the build and all testing-farm CI checks. + +This feature restores a working Fedora packaging pipeline across both repositories by: + +1. Simplifying the complyctl RPM spec to deliver only the `complyctl` binary. +2. Creating a new RPM spec in `complytime-providers` that produces two sub-packages: one for the OpenSCAP provider and one for the Ampel provider. +3. Establishing a dependency relationship where provider packages require complyctl, while complyctl can be installed standalone. +4. Adding testing-farm CI validation for each PR in both repositories. +5. Configuring Packit automation so that new releases automatically propagate to Fedora packages. + +All RPMs follow the Fedora Packaging Guidelines for Go projects, including bundled dependency declarations. + +Integration tests between complyctl and complytime-providers RPMs are explicitly out of scope and deferred to a separate specification. + +--- + +## Clarifications + +### Session 2026-04-24 + +- Q: Should the complytime-providers source RPM produce a main `complytime-providers` binary package alongside the sub-packages? → A: No main package. The source RPM produces only the two sub-packages (`complytime-providers-openscap` and `complytime-providers-ampel`); no `complytime-providers` binary RPM is published (Option A). +- Q: Should provider sub-packages use unversioned, minimum-version, or exact-match dependency on complyctl? → A: Minimum version (`Requires: complyctl >= X.Y.Z`) to ensure provider SDK compatibility; the exact version is determined at implementation time when the post-spec-004 release is tagged (Option B). + +--- + +## User Scenarios & Testing *(mandatory)* + +### User Story 1 - complyctl RPM Builds and Installs Cleanly (Priority: P1) + +A Fedora package maintainer submits a PR to the complyctl repository and the automated CI pipeline successfully builds an RPM containing only the `complyctl` binary, installs it on a test system, and validates the binary is functional. + +**Why this priority**: The complyctl RPM is currently broken after the provider split. Restoring a working RPM build is the prerequisite for all other packaging work and for unblocking CI on every PR. + +**Independent Test**: Open a PR against complyctl, observe the Packit/COPR build succeeds, and confirm the testing-farm job installs the RPM and runs basic validation commands (`complyctl version`, `complyctl --help`) without errors. + +**Acceptance Scenarios**: + +1. **Given** the updated complyctl RPM spec, **When** a COPR build is triggered by a PR, **Then** the build succeeds and produces a single `complyctl` binary RPM with no provider sub-packages. +2. **Given** the complyctl RPM installed on a Fedora system, **When** a user runs `complyctl version`, **Then** the command exits successfully and displays the version. +3. **Given** the complyctl RPM installed on a Fedora system, **When** a user runs `complyctl --help`, **Then** the command exits successfully and displays usage information. +4. **Given** the complyctl RPM spec, **When** reviewed against Fedora Packaging Guidelines for Go projects, **Then** the spec includes proper bundled dependency declarations, license metadata, and follows the standard Go RPM macros. + +--- + +### User Story 2 - Provider Sub-Packages Build From complytime-providers (Priority: P1) + +A package maintainer submits a PR to the `complytime-providers` repository and the CI pipeline builds a source RPM that produces two binary sub-packages: `complytime-providers-openscap` and `complytime-providers-ampel`. Each sub-package contains its respective provider binary installed to the standard provider discovery path. + +**Why this priority**: Equally critical to Story 1. Without working provider RPMs, Fedora users cannot install providers through the package manager. The provider packages depend on the complyctl package being available. + +**Independent Test**: Open a PR against complytime-providers, observe the Packit/COPR build succeeds, and confirm the testing-farm job installs each provider sub-package along with its complyctl dependency and validates the provider binaries are present at the expected filesystem locations. + +**Acceptance Scenarios**: + +1. **Given** the complytime-providers RPM spec, **When** a COPR build is triggered, **Then** two binary sub-packages are produced: `complytime-providers-openscap` and `complytime-providers-ampel`. +2. **Given** the `complytime-providers-openscap` RPM installed on a Fedora system, **When** a user checks the provider binary path, **Then** `complyctl-provider-openscap` is present at the standard provider directory. +3. **Given** the `complytime-providers-ampel` RPM installed on a Fedora system, **When** a user checks the provider binary path, **Then** `complyctl-provider-ampel` is present at the standard provider directory. +4. **Given** either provider sub-package, **When** installed via `dnf`, **Then** the `complyctl` package is automatically pulled in as a dependency. +5. **Given** the complytime-providers RPM spec, **When** reviewed against Fedora Packaging Guidelines for Go projects, **Then** the spec includes proper bundled dependency declarations, license metadata, and follows the standard Go RPM macros. + +--- + +### User Story 3 - complyctl Installs Without Providers (Priority: P2) + +A Fedora user installs the `complyctl` package without any provider packages. The installation succeeds and the CLI is functional for operations that do not require a provider (e.g., version display, help, workspace initialization). + +**Why this priority**: This validates the decoupled dependency model. complyctl must be independently installable since some users may only need the core tool or may install providers separately. + +**Independent Test**: Install `complyctl` RPM on a clean Fedora system without any provider packages and verify the binary runs, displays help, and exits cleanly. + +**Acceptance Scenarios**: + +1. **Given** a clean Fedora system with no provider packages installed, **When** a user installs only the `complyctl` RPM, **Then** the installation succeeds without dependency errors. +2. **Given** a Fedora system with only `complyctl` installed, **When** a user runs `complyctl version`, **Then** the command succeeds and shows version information. +3. **Given** a Fedora system with only `complyctl` installed, **When** a user attempts a scan operation that requires a provider, **Then** the CLI produces a clear message indicating no providers are available. + +--- + +### User Story 4 - Automated Fedora Package Updates on Release (Priority: P2) + +When a new version is tagged and released in either repository, Packit automatically proposes a downstream PR to the corresponding Fedora dist-git repository, submits Koji builds, and triggers Bodhi updates for released Fedora versions. + +**Why this priority**: Automation is essential for sustainable maintenance but is not blocking the initial RPM fix. Once the specs and CI are working (Stories 1-3), the release automation completes the pipeline. + +**Independent Test**: Create a release tag in the repository, observe that Packit creates a PR in the corresponding Fedora dist-git, and after merge, a Koji build and Bodhi update are triggered. + +**Acceptance Scenarios**: + +1. **Given** a new version tag pushed to the complyctl repository, **When** the Packit `propose_downstream` job triggers, **Then** a PR is created in the Fedora dist-git complyctl repository for each configured branch. +2. **Given** a new version tag pushed to the complytime-providers repository, **When** the Packit `propose_downstream` job triggers, **Then** a PR is created in the Fedora dist-git complytime-providers repository for each configured branch. +3. **Given** a merged PR in Fedora dist-git for either package, **When** the Packit `koji_build` job triggers, **Then** a Koji build is submitted for the corresponding branches. +4. **Given** a successful Koji build for a released Fedora version, **When** the Packit `bodhi_update` job triggers, **Then** a Bodhi update is created for the corresponding package. + +--- + +### User Story 5 - Testing-Farm Validates RPMs on Each PR (Priority: P2) + +Each PR submitted to either repository triggers testing-farm CI that builds the RPM from the PR source, installs it on a test system, and runs basic validation tests to catch packaging regressions before merge. + +**Why this priority**: CI validation ensures packaging quality over time. It prevents regressions where a code change inadvertently breaks the RPM build or the installed binary. + +**Independent Test**: Submit a PR with a trivial change and verify that testing-farm jobs appear in the PR checks, execute successfully, and their results are visible in the PR. + +**Acceptance Scenarios**: + +1. **Given** a PR submitted to the complyctl repository, **When** the Packit tests job triggers, **Then** a testing-farm job runs that installs the built RPM and validates the `complyctl` binary. +2. **Given** a PR submitted to the complytime-providers repository, **When** the Packit tests job triggers, **Then** a testing-farm job runs that installs both provider sub-packages and validates the provider binaries are present. +3. **Given** a testing-farm test run for either repository, **When** the test completes, **Then** the pass/fail result is reported back to the PR as a status check. + +--- + +### Edge Cases + +- What happens when a provider RPM is installed but the complyctl package is not yet available in the target Fedora version? The provider package declares a `Requires: complyctl` dependency, so `dnf` will refuse the installation if complyctl is not available, giving the user a clear dependency error. +- What happens when the complyctl and complytime-providers packages are at mismatched versions? Since integration tests are deferred, version compatibility is managed by the `Requires` dependency specifying a minimum compatible complyctl version. +- What happens when a COPR build succeeds but the testing-farm test fails? The PR status check reflects the failure, blocking merge until the packaging issue is resolved. +- What happens when the Fedora dist-git package for complytime-providers does not yet exist? The package must be registered in Fedora before Packit can propose downstream PRs. This is a one-time prerequisite handled by the package maintainer through the Fedora package review process. + +--- + +## Requirements *(mandatory)* + +### Functional Requirements + +#### complyctl RPM Spec Update + +- **FR-001**: The complyctl RPM spec MUST be updated to remove the `openscap-provider` sub-package section and all references to building or installing provider binaries. +- **FR-002**: The complyctl RPM spec MUST build only the `complyctl` binary from `cmd/complyctl/`. +- **FR-003**: The complyctl RPM spec MUST install the `complyctl` binary to `%{_bindir}` and the LICENSE file. +- **FR-004**: The complyctl RPM spec MUST retain the provider directory structure (`%{_libexecdir}/complytime/providers/`) as an owned directory so that provider packages can install into it. +- **FR-005**: The complyctl RPM spec MUST follow the Fedora Packaging Guidelines for Go projects, including proper use of Go RPM macros and bundled dependency declarations. +- **FR-006**: The complyctl RPM spec MUST declare all bundled Go dependencies using `Provides: bundled(golang(...))` entries, as required by Fedora for Go projects that vendor dependencies. +- **FR-007**: The complyctl RPM spec `%check` section MUST run the project's unit tests during the build. + +#### complytime-providers RPM Spec (New) + +- **FR-008**: A new RPM spec file MUST be created in the `complytime-providers` repository that builds both provider binaries from a single source package. +- **FR-009**: The spec MUST define two sub-packages: `complytime-providers-openscap` and `complytime-providers-ampel`. No main `complytime-providers` binary RPM is produced; the source RPM yields only these two sub-packages. +- **FR-010**: Each sub-package MUST install its respective provider binary (`complyctl-provider-openscap` or `complyctl-provider-ampel`) to the standard provider directory (`%{_libexecdir}/complytime/providers/`). +- **FR-011**: Each sub-package MUST declare a dependency on the `complyctl` package using `Requires: complyctl >= X.Y.Z`, where `X.Y.Z` is the first complyctl release containing the provider SDK (`pkg/provider/`). The exact version is determined at implementation time. +- **FR-012**: The `complytime-providers-openscap` sub-package MUST declare a dependency on `scap-security-guide` since the OpenSCAP provider requires SCAP content to function. +- **FR-013**: The complytime-providers RPM spec MUST follow the Fedora Packaging Guidelines for Go projects, including proper use of Go RPM macros and bundled dependency declarations. +- **FR-014**: The complytime-providers RPM spec MUST declare all bundled Go dependencies using `Provides: bundled(golang(...))` entries. +- **FR-015**: The complytime-providers RPM spec `%check` section MUST run the project's unit tests during the build. + +#### Packit Configuration + +- **FR-016**: The complyctl `.packit.yaml` MUST be updated to reflect the simplified spec (no provider-related file syncing changes expected, but the file list MUST match actual deliverables). +- **FR-017**: A `.packit.yaml` MUST be created in the `complytime-providers` repository with COPR build, testing-farm tests, propose-downstream, Koji build, and Bodhi update jobs. +- **FR-018**: Both Packit configurations MUST target the same set of Fedora and CentOS Stream versions for COPR builds and testing-farm tests (currently: Fedora rawhide, Fedora 43, Fedora 42, CentOS Stream 9, CentOS Stream 10). +- **FR-019**: Both Packit configurations MUST include `propose_downstream`, `koji_build`, and `bodhi_update` jobs for release automation against the appropriate dist-git branches. + +#### Testing-Farm / TMT Plans + +- **FR-020**: The complyctl repository MUST have a TMT test plan that validates the installed `complyctl` RPM binary is functional (at minimum: `complyctl version` and `complyctl --help` succeed). +- **FR-021**: The `complytime-providers` repository MUST have TMT test plan(s) that validate each installed provider sub-package binary is present at the expected location and executable. +- **FR-022**: Both repositories MUST have the FMF metadata root (`.fmf/version` file) so that testing-farm can discover and execute TMT plans. + +#### Release Process and Documentation + +- **FR-023**: The complyctl `.goreleaser.yaml` MUST be updated to remove the `openscap-plugin` build entry, since `cmd/openscap-plugin/` no longer exists after the repository split. Only the `complyctl` binary MUST be built by GoReleaser. +- **FR-024**: The `docs/RELEASE_PROCESS.md` MUST be updated to reflect that providers are now a separate Fedora package (`complytime-providers`) with an independent release cycle and Packit automation. +- **FR-025**: The complyctl RPM spec MUST install the `complyctl.1` man page to the standard man page directory. The man page source (`docs/man/complyctl.md`) MUST be updated with provider terminology before regeneration via `make man`. +- **FR-026**: The `docs/man/complyctl.md` man page source MUST use "provider" terminology consistently (replacing any remaining "plugin" references) and be regenerated into `docs/man/complyctl.1` before the RPM source tarball is produced. + +#### Scope Boundaries + +- **FR-027**: Integration tests that validate complyctl and providers work together as installed RPMs are explicitly out of scope and MUST NOT be included in this feature. They are deferred to a separate specification. + +### Key Entities + +- **complyctl RPM**: The Fedora package that delivers the `complyctl` CLI binary. Installable standalone. Owns the provider directory structure. +- **complytime-providers source RPM**: A single source package in Fedora that builds from the `complytime-providers` upstream repository and produces only two binary sub-packages (no main binary RPM is published). +- **complytime-providers-openscap**: A binary sub-package containing the OpenSCAP provider binary. Requires complyctl and scap-security-guide. +- **complytime-providers-ampel**: A binary sub-package containing the Ampel provider binary. Requires complyctl. +- **TMT plan**: A test metadata tree (tmt) definition that testing-farm executes to validate installed RPMs. Defined as `.fmf` files in the `plans/` directory. +- **Packit configuration**: A `.packit.yaml` file that drives the CI/CD pipeline: COPR builds on PRs, testing-farm tests on PRs, and downstream Fedora automation on releases. + +--- + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001**: The complyctl RPM builds successfully from the updated spec, producing a single binary package with no provider sub-packages. +- **SC-002**: The complytime-providers RPM builds successfully, producing two binary sub-packages (`complytime-providers-openscap` and `complytime-providers-ampel`). +- **SC-003**: Installing a provider sub-package via `dnf` automatically resolves and installs the `complyctl` dependency. +- **SC-004**: Installing the `complyctl` RPM on a clean system without providers succeeds, and `complyctl version` exits with code 0. +- **SC-005**: PRs to the complyctl repository trigger COPR build and testing-farm jobs that pass, validating the RPM is functional. +- **SC-006**: PRs to the complytime-providers repository trigger COPR build and testing-farm jobs that pass, validating both provider sub-packages are functional. +- **SC-007**: A release tag on the complyctl repository triggers Packit to propose a downstream PR to the Fedora dist-git complyctl package. +- **SC-008**: A release tag on the complytime-providers repository triggers Packit to propose a downstream PR to the Fedora dist-git complytime-providers package. +- **SC-009**: Both RPM specs pass Fedora package review criteria for Go projects, including bundled dependency declarations and proper license fields. +- **SC-010**: The complyctl GoReleaser build (`goreleaser check` and `goreleaser build --snapshot`) succeeds without referencing the removed openscap-plugin directory. +- **SC-011**: The `complyctl.1` man page is present in the installed complyctl RPM. + +--- + +## Assumptions + +- The `complytime-providers` Fedora package does not yet exist in Fedora dist-git. A Fedora package review request must be filed and approved before the `propose_downstream` and `koji_build` Packit jobs can function. This is a manual, one-time prerequisite outside the scope of this specification. +- The complyctl Fedora package already exists in Fedora dist-git and the existing Packit integration continues to work after the spec update. +- Both repositories use Go module vendoring (dependencies committed under `vendor/`), which is the standard approach for Fedora Go RPM packaging with bundled dependencies. +- The `complyctl` provider directory (`/usr/libexec/complytime/providers/`) is owned by the complyctl RPM. Provider sub-packages install files into this directory without owning it. +- The Packit service has access to both the `complytime/complyctl` and `complytime/complytime-providers` GitHub repositories. +- Testing-farm tests perform basic smoke tests only (binary presence, version output, help output). They do not validate provider-complyctl interaction. Integration tests are explicitly deferred. +- The minimum `complyctl` version required by providers corresponds to the first release that includes the provider SDK rename from spec 004 (`pkg/provider/`). The exact version number is determined at implementation time when the release is tagged. + +--- + +## Dependencies + +- **Spec 004 (Providers Repository Split)**: Must be completed before this feature can be fully implemented. The complyctl codebase must have providers removed and the `complytime-providers` repository must contain the provider source code. +- **complyctl tagged release**: A tagged release of complyctl with the provider SDK (`pkg/provider/`) must be published before the complytime-providers spec can declare a versioned `Requires: complyctl >= X.Y.Z`. +- **Fedora package review for complytime-providers**: A new package review request must be filed and approved in Fedora before downstream automation can function. This is a manual prerequisite. +- **Packit access to complytime-providers**: The Packit service must be enabled on the `complytime/complytime-providers` GitHub repository. diff --git a/specs/005-rpm-packaging-ci/tasks.md b/specs/005-rpm-packaging-ci/tasks.md new file mode 100644 index 00000000..8619a961 --- /dev/null +++ b/specs/005-rpm-packaging-ci/tasks.md @@ -0,0 +1,248 @@ +# Tasks: RPM Packaging and CI for Split Repositories + +**Input**: Design documents from `/specs/005-rpm-packaging-ci/` +**Prerequisites**: plan.md (required), spec.md (required), research.md, data-model.md, contracts/ + +## Format: `[ID] [P?] [Story] Description` + +- **[P]**: Can run in parallel (different files, no dependencies) +- **[Story]**: Which user story this task belongs to (e.g., US1, US2) +- Includes exact file paths in descriptions + +## Repositories + +This feature spans two repositories: + +- **complyctl** (this repo): `/home/maburgha/GIT/ProdSec/complyctl/` +- **complytime-providers** (external): `github.com/complytime/complytime-providers` + +Tasks for complytime-providers are marked with `[providers-repo]` and must be +executed in a clone of that repository. + +--- + +## Phase 1: Foundational (Blocking Prerequisites) + +**Purpose**: Updates that MUST be complete before RPM spec work can begin + +- [x] T001 Update man page source with provider terminology in docs/man/complyctl.md -- replace any remaining "plugin" references with "provider" throughout the file. The file uses pandoc man page format (% header lines, # sections). Preserve the pandoc metadata header. Review all sections: NAME, SYNOPSIS, DESCRIPTION, COMMANDS, OPTIONS, FILES, EXAMPLES, SEE ALSO. Ensure references to provider binaries use the `complyctl-provider-` naming convention and discovery paths match `/usr/libexec/complytime/providers/` and `~/.complytime/providers/`. +- [x] T002 Regenerate man page from updated source by running `make man` in the complyctl repository root. This produces docs/man/complyctl.1 from docs/man/complyctl.md using pandoc. Verify the output file is updated. Requires pandoc to be installed. If pandoc is not available, note the dependency for CI but do not block -- the pre-built complyctl.1 in the repo is acceptable for now. + +**Checkpoint**: Man page source and generated output are ready. RPM spec work can begin. + +--- + +## Phase 2: User Story 1 - complyctl RPM Builds and Installs Cleanly (Priority: P1) + +**Goal**: Fix the broken complyctl RPM spec so it builds only the complyctl binary (no provider sub-packages), includes the man page, and follows Fedora Go packaging guidelines with automatic bundled dependency declarations. + +**Independent Test**: Run `rpmbuild -bs complyctl.spec` or `packit build locally` and verify a single `complyctl` binary RPM is produced with no provider sub-packages. Verify `rpm -qlp` shows `/usr/bin/complyctl`, man page, LICENSE, and owned provider directories. + +### Implementation for User Story 1 + +- [x] T003 [US1] Rewrite complyctl.spec to remove provider sub-package and simplify for core-only delivery. Specific changes to complyctl.spec: + **Preamble**: Keep `%global goipath`, `%global base_url`, `%global app_dir complytime`, `%global debug_package %{nil}`. Evaluate `%global gopath %{_builddir}/go` (line 6 of current spec) -- this overrides the default from `go-rpm-macros`. Keep it only if the build fails without it; otherwise remove it to align with standard Go RPM macro behavior. Update `Summary` to remove "pluggable providers" language (use "provider" if mentioned). Change `Release: 0%{?dist}` to `Release: 1%{?dist}` (standard Fedora convention for released versions). Keep `BuildRequires: golang` and `BuildRequires: go-rpm-macros`. Keep `%gometa -f`. + **Remove entirely**: The `%package openscap-provider` section, its `Summary`, `Requires`, and `%description openscap-provider` block. Remove `%files openscap-provider` section. + **%build section**: Remove `cd cmd/openscap-plugin` build step and the `cd ../..` return. Change `go build ... ./cmd/...` to `go build -buildmode=pie -o ${GO_BUILD_BINDIR}/complyctl -ldflags="${GO_LD_EXTRAFLAGS}" ./cmd/complyctl`. Keep the `%set_build_flags`, `GO_LD_EXTRAFLAGS`, `GO111MODULE=on`, and `BUILD_DATE_GO` setup as-is. + **%install section**: Remove `install ... complyctl-provider-openscap` line. Keep `install ... complyctl` line. Add man page: `install -d %{buildroot}%{_mandir}/man1` and `install -p -m 0644 docs/man/complyctl.1 %{buildroot}%{_mandir}/man1/complyctl.1`. Keep the provider directory creation (`install -d ... providers`). Do NOT manually install `vendor/modules.txt` here -- RPM's `%license` directive in `%files` handles it automatically (same mechanism used for LICENSE today). + **%check section**: Remove `cd cmd/openscap-plugin && go test ...` and `cd ../..`. Keep `go test -mod=vendor -race -v ./...` (alternatively, use `%gocheck` which is the standard Fedora Go macro and handles `-race` flag availability per architecture automatically -- the `-race` flag requires CGO which may not be available on all build targets). + **%files section**: Keep `%attr(0755, root, root) %{_bindir}/complyctl`. Add `%{_mandir}/man1/complyctl.1*`. Change `%license LICENSE` to `%license LICENSE vendor/modules.txt`. Add `%doc README.md`. Keep `%dir %{_libexecdir}/%{app_dir}` and `%dir %{_libexecdir}/%{app_dir}/providers`. Remove the `Requires: scap-security-guide` (now in providers spec). + **%changelog**: Add new entry for the current date. + **References**: FR-001 through FR-007, FR-025, SC-001, SC-011. See data-model.md for file ownership layout. + +- [x] T004 [P] [US1] Verify complyctl .packit.yaml needs no changes for simplified spec in .packit.yaml -- the existing config references `complyctl.spec` and syncs `complyctl.spec` + `.packit.yaml`. This should still be correct after the spec update. Verify `specfile_path`, `files_to_sync`, and all job configurations are valid. No changes expected (FR-016). + +**Checkpoint**: complyctl RPM spec builds a single binary package. `rpmlint complyctl.spec` passes. The existing TMT plan (`plans/test-RPM-provide-content.fmf`) and FMF root (`.fmf/version`) are already in place (FR-020, FR-022). + +--- + +## Phase 3: User Story 2 - Provider Sub-Packages Build From complytime-providers (Priority: P1) + +**Goal**: Create a complete RPM packaging pipeline in the complytime-providers repository: spec file producing two sub-packages, Packit CI/CD, FMF metadata, and TMT smoke tests. + +**Independent Test**: In the complytime-providers repo, run `rpmbuild -bs complytime-providers.spec` and verify two binary sub-packages are produced (`complytime-providers-openscap` and `complytime-providers-ampel`) with no main package. Verify `rpm -qp --requires` shows `complyctl >= X.Y.Z`. + +**NOTE**: All tasks in this phase are executed in the `complytime-providers` repository. + +### Implementation for User Story 2 + +- [x] T005 [P] [US2] [providers-repo] Create complytime-providers.spec in the complytime-providers repository root. The spec must follow the Fedora Go packaging guidelines with vendored dependencies. Structure: + **First line**: `# SPDX-License-Identifier: Apache-2.0` (required by constitution for all source files). + **Preamble**: `%global goipath github.com/complytime/complytime-providers`, `%global base_url https://%{goipath}`, `%global app_dir complytime`, `%global debug_package %{nil}`. Do NOT include `%global gopath` -- let `go-rpm-macros` manage the build directory via `%goprep`. `Name: complytime-providers`, `Version:` (set to current or `0.0.1`), `Release: 1%{?dist}`, `Summary: Compliance scanning providers for complyctl`, `License: Apache-2.0`, `URL: %{base_url}`, `Source0: %{base_url}/archive/refs/tags/v%{version}.tar.gz`. `BuildRequires: golang` and `BuildRequires: go-rpm-macros`. `%gometa -f`. Main `%description` describes the source package purpose. + **Sub-packages**: `%package openscap` with `Summary: OpenSCAP scanning provider for complyctl`, `Requires: complyctl >= X.Y.Z` (set X.Y.Z to the first post-spec-004 release version), `Requires: scap-security-guide`. `%description openscap` explains the OpenSCAP provider. `%package ampel` with `Summary: Ampel scanning provider for complyctl`, `Requires: complyctl >= X.Y.Z`. `%description ampel` explains the Ampel provider. + **%prep**: `%goprep -k` (preserves vendor directory). + **%build**: `%set_build_flags`, `export GO111MODULE=on`, `GO_BUILD_BINDIR=./bin`, `mkdir -p ${GO_BUILD_BINDIR}`. Build both: `go build -buildmode=pie -o ${GO_BUILD_BINDIR}/complyctl-provider-openscap ./cmd/openscap-provider` and `go build -buildmode=pie -o ${GO_BUILD_BINDIR}/complyctl-provider-ampel ./cmd/ampel-provider`. No version injection LD flags needed (providers have no version package). + **%install**: `install -d %{buildroot}%{_libexecdir}/%{app_dir}/providers`. Install both binaries with `install -p -m 0755`. Do NOT manually install `vendor/modules.txt` -- RPM's `%license` directive in `%files` handles it automatically. + **%check**: `go test -mod=vendor -v ./...` (alternatively, use `%gocheck` which is the standard Fedora Go macro and handles `-race` flag availability per architecture automatically). + **No main %files section** (no main binary RPM produced). `%files openscap`: provider binary, `%license LICENSE vendor/modules.txt`, `%doc README.md`. `%files ampel`: provider binary, `%license LICENSE vendor/modules.txt`, `%doc README.md`. + **%changelog**: Initial entry. + **References**: FR-008 through FR-015, SC-002, SC-003. See data-model.md and contracts/packaging-interface.md. + +- [x] T006 [P] [US2] [providers-repo] Create .packit.yaml in the complytime-providers repository root. Model it after the complyctl .packit.yaml with these values: `upstream_project_url: https://github.com/complytime/complytime-providers`, `upstream_tag_template: v{version}`, `upstream_package_name: complytime-providers`, `downstream_package_name: complytime-providers`, `specfile_path: complytime-providers.spec`, `files_to_sync: [complytime-providers.spec, .packit.yaml]`. Jobs: `copr_build` (trigger: pull_request, targets: fedora-rawhide-x86_64, fedora-43-x86_64, fedora-42-x86_64, centos-stream-9-x86_64, centos-stream-10-x86_64), `tests` (same trigger and targets), `propose_downstream` (trigger: release, dist_git_branches: rawhide, f43, f42), `koji_build` (trigger: commit, same branches), `bodhi_update` (trigger: commit, dist_git_branches: f43, f42). References: FR-017, FR-018, FR-019. + +- [x] T007 [P] [US2] [providers-repo] Create FMF metadata root at .fmf/version in the complytime-providers repository. Create the directory `.fmf/` and write a single file `version` containing just `1` (no trailing newline or extra content). This enables testing-farm to discover TMT plans. Reference: FR-022. + +- [x] T008 [P] [US2] [providers-repo] Create TMT test plan at plans/test-RPM-providers.fmf in the complytime-providers repository. Create the `plans/` directory. The plan validates that both provider binaries are installed at the expected path after RPM installation. Content: + ``` + summary: Validate complytime-providers RPM sub-packages deliver provider binaries + + execute: + script: + - test -x /usr/libexec/complytime/providers/complyctl-provider-openscap + - test -x /usr/libexec/complytime/providers/complyctl-provider-ampel + ``` + This uses `test -x` to verify files exist and are executable. Matches the inline script pattern used by complyctl's existing TMT plan. Reference: FR-021. See contracts/packaging-interface.md TMT Test Contract section. + +**Checkpoint**: complytime-providers repo has a complete packaging pipeline. `rpmlint complytime-providers.spec` passes. Both sub-packages build successfully. TMT plan is discoverable. + +--- + +## Phase 4: User Story 3 - complyctl Installs Without Providers (Priority: P2) + +**Goal**: Validate that the complyctl RPM installs and operates correctly on a system with no provider packages installed. + +**Independent Test**: Install the complyctl RPM on a clean Fedora system (or mock chroot). Verify `complyctl version` and `complyctl --help` succeed. Verify no provider-related dependency errors occur. + +**NOTE**: This story requires no new files. It is validated by the US1 implementation -- the updated complyctl.spec produces a standalone RPM with no provider dependencies. + +### Validation for User Story 3 + +- [x] T009 [US3] Validate complyctl RPM has no provider dependencies by inspecting the built RPM: run `rpm -qp --requires` on the built complyctl RPM and verify no `complytime-providers` or `scap-security-guide` entries appear. Verify the `%files` section does not include any provider binaries. This confirms FR-001, FR-003, SC-004. + +**Checkpoint**: complyctl is confirmed independently installable without providers. + +--- + +## Phase 5: User Story 4 - Automated Fedora Package Updates on Release (Priority: P2) + +**Goal**: Ensure the release pipeline works end-to-end: GoReleaser produces a clean GitHub release for complyctl, Packit reacts to releases in both repos, and the release process documentation reflects the new split structure. + +**Independent Test**: Run `goreleaser check` and `goreleaser build --snapshot --clean` in complyctl repo. Verify no errors referencing `openscap-plugin`. Review RELEASE_PROCESS.md for accuracy. + +### Implementation for User Story 4 + +- [x] T010 [P] [US4] Update .goreleaser.yaml to remove the openscap-plugin build entry. Remove lines 27-31 (the entire `- id: openscap-plugin` build block including `binary`, `dir`, `main`, and `goos` fields). Keep the `- id: complyctl` build block unchanged. Run `goreleaser check` to validate syntax. Run `goreleaser build --snapshot --clean` to verify only the complyctl binary is produced. Reference: FR-023, SC-010. + +- [x] T011 [P] [US4] Update docs/RELEASE_PROCESS.md to reflect the split packaging structure. Add a new section or update the existing "Fedora Package" section to note: (1) complyctl and complytime-providers are now independent Fedora packages with separate release cycles. (2) Each repository has its own `.packit.yaml` that automates downstream PRs, Koji builds, and Bodhi updates. (3) The complytime-providers Fedora package requires a one-time Fedora package review before automation is functional. (4) Link to the complytime-providers repository. Keep the existing manual fallback process documentation. Reference: FR-024. + +**Checkpoint**: GoReleaser builds cleanly. Release documentation is accurate for the new multi-repo structure. + +--- + +## Phase 6: User Story 5 - Testing-Farm Validates RPMs on Each PR (Priority: P2) + +**Goal**: Confirm both repositories have the complete testing-farm integration: FMF metadata root, TMT plans, and Packit `tests` job configuration. + +**Independent Test**: Run `tmt lint` in both repos. Verify Packit configs include `tests` jobs. Submit a PR to validate testing-farm triggers. + +**NOTE**: This story requires no new files. The testing-farm infrastructure is delivered by US1 (complyctl already has TMT plan + Packit tests job) and US2 (complytime-providers gets TMT plan + Packit tests job). + +### Validation for User Story 5 + +- [x] T012 [US5] Validate testing-farm readiness in both repositories. In complyctl: verify `.fmf/version` exists, `plans/test-RPM-provide-content.fmf` exists and is valid, and `.packit.yaml` includes a `tests` job. In complytime-providers: verify `.fmf/version`, `plans/test-RPM-providers.fmf`, and `.packit.yaml` `tests` job are all present. Run `tmt lint` in both repos if tmt is available. References: FR-020, FR-021, FR-022, SC-005, SC-006. + +**Checkpoint**: Both repos are ready for testing-farm CI on PRs. + +--- + +## Phase 7: Polish & Cross-Cutting Concerns + +**Purpose**: Final validation and cleanup across both repositories + +- [x] T013 [P] Run rpmlint on complyctl.spec and fix any warnings or errors. Focus on: license field, summary length, description quality, macro usage, file permissions. +- [x] T014 [P] Run rpmlint on complytime-providers.spec (in providers repo) and fix any warnings or errors. +- [x] T015 Verify Packit configuration validity by running `packit validate-config` in both repos (if packit CLI is available). Confirm all job triggers, targets, and dist-git branches are correct per the CI target matrix in data-model.md. + +--- + +## Dependencies & Execution Order + +### Phase Dependencies + +- **Foundational (Phase 1)**: No dependencies -- can start immediately +- **US1 (Phase 2)**: Depends on Foundational (man page must be ready for RPM spec) +- **US2 (Phase 3)**: No dependency on US1 -- can start in parallel (different repo) +- **US3 (Phase 4)**: Depends on US1 completion (validates the complyctl RPM) +- **US4 (Phase 5)**: Can start after Foundational (GoReleaser + docs are independent files) +- **US5 (Phase 6)**: Depends on US1 + US2 (validates infrastructure from both) +- **Polish (Phase 7)**: Depends on US1 + US2 + US4 + +### User Story Dependencies + +- **US1 (P1)**: Depends on Foundational only. Produces: updated complyctl.spec +- **US2 (P1)**: Independent of US1. Produces: complytime-providers.spec, .packit.yaml, .fmf/version, TMT plan +- **US3 (P2)**: Depends on US1. Validation only (no new files) +- **US4 (P2)**: Depends on Foundational only. Produces: updated .goreleaser.yaml, updated RELEASE_PROCESS.md +- **US5 (P2)**: Depends on US1 + US2. Validation only (no new files) + +### Parallel Opportunities + +- **US1 and US2 can run in parallel** (different repos, no shared files) +- **US1 and US4 can run in parallel** after Foundational (different files in same repo) +- **Within US2**: All 4 tasks (T005-T008) can run in parallel (different files) +- **Within US4**: T010 and T011 can run in parallel (different files) +- **Polish**: T013 and T014 can run in parallel (different repos) + +--- + +## Parallel Example: US1 + US2 + US4 After Foundational + +```text +# After Foundational (T001, T002) completes: + +# Stream A (complyctl repo - US1): +Task: T003 "Rewrite complyctl.spec" +Task: T004 "Verify .packit.yaml" + +# Stream B (complytime-providers repo - US2, all parallel): +Task: T005 "Create complytime-providers.spec" +Task: T006 "Create .packit.yaml" +Task: T007 "Create .fmf/version" +Task: T008 "Create plans/test-RPM-providers.fmf" + +# Stream C (complyctl repo - US4, parallel with Stream A): +Task: T010 "Update .goreleaser.yaml" +Task: T011 "Update RELEASE_PROCESS.md" +``` + +--- + +## Implementation Strategy + +### MVP First (US1 Only) + +1. Complete Foundational (T001-T002) -- man page update +2. Complete US1 (T003-T004) -- fix complyctl RPM +3. **STOP and VALIDATE**: `rpmlint complyctl.spec`, test local build +4. Submit PR to complyctl -- Packit/COPR build + testing-farm validates + +### Incremental Delivery + +1. Foundational → man page ready +2. US1 → complyctl RPM fixed → PR validates via existing CI (MVP!) +3. US2 → complytime-providers has packaging → PR validates via new CI +4. US4 → GoReleaser + docs updated → release pipeline unblocked +5. US3 + US5 → validation confirms everything works together +6. Polish → rpmlint + packit validate-config clean + +### Parallel Strategy + +With two developers or agents: + +1. Both complete Foundational together +2. Once Foundational is done: + - Agent A: US1 (complyctl spec) + US4 (goreleaser + docs) + - Agent B: US2 (complytime-providers, all 4 tasks in parallel) +3. Both validate: US3, US5, Polish + +--- + +## Notes + +- [P] tasks = different files, no dependencies on incomplete tasks +- [providers-repo] = execute in complytime-providers clone, not complyctl +- US3 and US5 are validation-only (no new implementation files) +- The `Requires: complyctl >= X.Y.Z` version in complytime-providers.spec must be set to the actual first post-spec-004 complyctl release version at implementation time +- Fedora package review for complytime-providers is a manual prerequisite outside this task list +- Commit after each task or logical group +- Stop at any checkpoint to validate independently