diff --git a/.github/workflows/generator-generic-ossf-slsa3-publish.yml b/.github/workflows/generator-generic-ossf-slsa3-publish.yml index 35c829b..68dfb3f 100644 --- a/.github/workflows/generator-generic-ossf-slsa3-publish.yml +++ b/.github/workflows/generator-generic-ossf-slsa3-publish.yml @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR AGPL-3.0-or-later # This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support @@ -16,6 +17,8 @@ on: release: types: [created] +permissions: read-all + jobs: build: runs-on: ubuntu-latest @@ -23,7 +26,7 @@ jobs: digests: ${{ steps.hash.outputs.digests }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 # ======================================================== # diff --git a/.github/workflows/guix-nix-policy.yml b/.github/workflows/guix-nix-policy.yml index a776006..f5ddcc4 100644 --- a/.github/workflows/guix-nix-policy.yml +++ b/.github/workflows/guix-nix-policy.yml @@ -1,10 +1,14 @@ +# SPDX-License-Identifier: MIT OR AGPL-3.0-or-later name: Guix/Nix Package Policy on: [push, pull_request] + +permissions: read-all + jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Enforce Guix primary / Nix fallback run: | # Check for package manager files diff --git a/.github/workflows/jekyll-gh-pages.yml b/.github/workflows/jekyll-gh-pages.yml index e31d81c..734cb23 100644 --- a/.github/workflows/jekyll-gh-pages.yml +++ b/.github/workflows/jekyll-gh-pages.yml @@ -1,44 +1,37 @@ -# Sample workflow for building and deploying a Jekyll site to GitHub Pages +# SPDX-License-Identifier: MIT OR AGPL-3.0-or-later +# Workflow for building and deploying a Jekyll site to GitHub Pages name: Deploy Jekyll with GitHub Pages dependencies preinstalled on: - # Runs on pushes targeting the default branch push: - branches: ["main"] - - # Allows you to run this workflow manually from the Actions tab + branches: [main] workflow_dispatch: -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. concurrency: group: "pages" cancel-in-progress: false jobs: - # Build job build: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Setup Pages - uses: actions/configure-pages@v5 + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 - name: Build with Jekyll - uses: actions/jekyll-build-pages@v1 + uses: actions/jekyll-build-pages@44a6e6beabd48582f863aeeb6cb2151cc1716571 # v1.0.13 with: source: ./ destination: ./_site - name: Upload artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1 - # Deployment job deploy: environment: name: github-pages @@ -48,4 +41,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 diff --git a/.github/workflows/npm-bun-blocker.yml b/.github/workflows/npm-bun-blocker.yml index e19c080..a9d03c6 100644 --- a/.github/workflows/npm-bun-blocker.yml +++ b/.github/workflows/npm-bun-blocker.yml @@ -1,10 +1,14 @@ +# SPDX-License-Identifier: MIT OR AGPL-3.0-or-later name: NPM/Bun Blocker on: [push, pull_request] + +permissions: read-all + jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Block npm/bun run: | if [ -f "package-lock.json" ] || [ -f "bun.lockb" ] || [ -f ".npmrc" ]; then diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index eb78d2c..7657ab5 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR AGPL-3.0-or-later name: Code Quality on: [push, pull_request] @@ -5,44 +6,44 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Check file permissions run: | find . -type f -perm /111 -name "*.sh" | head -10 || true - + - name: Check for secrets - uses: trufflesecurity/trufflehog@main + uses: trufflesecurity/trufflehog@8a8ef8526f86c1dcf54f065f3d1d20aba814a6c1 # v3.82.8 with: path: ./ base: ${{ github.event.pull_request.base.sha || github.event.before }} head: ${{ github.sha }} continue-on-error: true - + - name: Check TODO/FIXME run: | echo "=== TODOs ===" grep -rn "TODO\|FIXME\|HACK\|XXX" --include="*.rs" --include="*.res" --include="*.py" --include="*.ex" . | head -20 || echo "None found" - + - name: Check for large files run: | find . -type f -size +1M -not -path "./.git/*" | head -10 || echo "No large files" - + - name: EditorConfig check - uses: editorconfig-checker/action-editorconfig-checker@main + uses: editorconfig-checker/action-editorconfig-checker@8554b65da4ba74e3d14fc0b64f3dc2cb99c6d63d # v2.0.0 continue-on-error: true docs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Check documentation run: | MISSING="" [ ! -f "README.md" ] && [ ! -f "README.adoc" ] && MISSING="$MISSING README" [ ! -f "LICENSE" ] && [ ! -f "LICENSE.txt" ] && [ ! -f "LICENSE.md" ] && MISSING="$MISSING LICENSE" [ ! -f "CONTRIBUTING.md" ] && [ ! -f "CONTRIBUTING.adoc" ] && MISSING="$MISSING CONTRIBUTING" - + if [ -n "$MISSING" ]; then echo "::warning::Missing docs:$MISSING" else diff --git a/.github/workflows/rsr-antipattern.yml b/.github/workflows/rsr-antipattern.yml index ac08939..f62c4a2 100644 --- a/.github/workflows/rsr-antipattern.yml +++ b/.github/workflows/rsr-antipattern.yml @@ -1,5 +1,5 @@ +# SPDX-License-Identifier: MIT OR AGPL-3.0-or-later # RSR Anti-Pattern CI Check -# SPDX-License-Identifier: AGPL-3.0-or-later # # Enforces: No TypeScript, No Go, No Python (except SaltStack), No npm # Allows: ReScript, Deno, WASM, Rust, OCaml, Haskell, Guile/Scheme @@ -12,11 +12,13 @@ on: pull_request: branches: [main, master, develop] +permissions: read-all + jobs: antipattern-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Check for TypeScript run: | diff --git a/.github/workflows/rust-ci.yml b/.github/workflows/rust-ci.yml index 2c0841a..f80293d 100644 --- a/.github/workflows/rust-ci.yml +++ b/.github/workflows/rust-ci.yml @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR AGPL-3.0-or-later name: Rust CI on: [push, pull_request] env: @@ -8,29 +9,29 @@ jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: dtolnay/rust-toolchain@1482605bfc5719782e1267fd0c0cc350fe7646b8 # stable with: components: rustfmt, clippy - - uses: Swatinem/rust-cache@v2 - + - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075ebd2b0e7570e8ddc6a # v2.7.3 + - name: Check formatting run: cargo fmt --all -- --check - + - name: Clippy lints run: cargo clippy --all-targets --all-features -- -D warnings - + - name: Run tests run: cargo test --all-features - + - name: Build release run: cargo build --release security: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: dtolnay/rust-toolchain@1482605bfc5719782e1267fd0c0cc350fe7646b8 # stable - name: Install cargo-audit run: cargo install cargo-audit - name: Security audit @@ -41,12 +42,12 @@ jobs: coverage: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@stable + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: dtolnay/rust-toolchain@1482605bfc5719782e1267fd0c0cc350fe7646b8 # stable - name: Install tarpaulin run: cargo install cargo-tarpaulin - name: Generate coverage run: cargo tarpaulin --out Xml - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 with: files: cobertura.xml diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 85fbdc7..1952704 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,22 +1,23 @@ +# SPDX-License-Identifier: MIT OR AGPL-3.0-or-later name: Rust on: push: - branches: [ "claude/conflow-architecture-design-01LjBsqMdiWLBTXEig4tJS6p" ] + branches: [main, master] pull_request: - branches: [ "claude/conflow-architecture-design-01LjBsqMdiWLBTXEig4tJS6p" ] + branches: [main, master] + +permissions: read-all env: CARGO_TERM_COLOR: always jobs: build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Build - run: cargo build --verbose - - name: Run tests - run: cargo test --verbose + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Build + run: cargo build --verbose + - name: Run tests + run: cargo test --verbose diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index a073b17..ef11c1d 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR AGPL-3.0-or-later name: OSSF Scorecard on: push: @@ -14,17 +15,17 @@ jobs: security-events: write id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - + - name: Run Scorecard - uses: ossf/scorecard-action@v2.3.1 + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 with: results_file: results.sarif results_format: sarif - + - name: Upload results - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@662472033e021d55d94146f66f6058822b0b39fd # v3.28.1 with: sarif_file: results.sarif diff --git a/.github/workflows/security-policy.yml b/.github/workflows/security-policy.yml index 90c2378..a1753f9 100644 --- a/.github/workflows/security-policy.yml +++ b/.github/workflows/security-policy.yml @@ -4,20 +4,20 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Security checks run: | FAILED=false - + # Block MD5/SHA1 for security (allow for checksums/caching) WEAK_CRYPTO=$(grep -rE 'md5\(|sha1\(' --include="*.py" --include="*.rb" --include="*.js" --include="*.ts" --include="*.go" --include="*.rs" . 2>/dev/null | grep -v 'checksum\|cache\|test\|spec' | head -5 || true) if [ -n "$WEAK_CRYPTO" ]; then echo "⚠️ Weak crypto (MD5/SHA1) detected. Use SHA256+ for security:" echo "$WEAK_CRYPTO" fi - + # Block HTTP URLs (except localhost) - HTTP_URLS=$(grep -rE 'https://[^l][^o][^c]' --include="*.py" --include="*.js" --include="*.ts" --include="*.go" --include="*.rs" --include="*.yaml" --include="*.yml" . 2>/dev/null | grep -v 'localhost\|127.0.0.1\|example\|test\|spec' | head -5 || true) + HTTP_URLS=$(grep -rE 'http://[^l][^o][^c]' --include="*.py" --include="*.js" --include="*.ts" --include="*.go" --include="*.rs" --include="*.yaml" --include="*.yml" . 2>/dev/null | grep -v 'localhost\|127.0.0.1\|example\|test\|spec' | head -5 || true) if [ -n "$HTTP_URLS" ]; then echo "⚠️ HTTP URLs found. Use HTTPS:" echo "$HTTP_URLS" diff --git a/.github/workflows/wellknown-enforcement.yml b/.github/workflows/wellknown-enforcement.yml index 809d209..91cc66b 100644 --- a/.github/workflows/wellknown-enforcement.yml +++ b/.github/workflows/wellknown-enforcement.yml @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: MIT OR AGPL-3.0-or-later name: Well-Known Standards (RFC 9116 + RSR) on: push: @@ -9,15 +10,16 @@ on: paths: - '.well-known/**' schedule: - # Weekly expiry check - cron: '0 9 * * 1' workflow_dispatch: +permissions: read-all + jobs: validate: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: RFC 9116 security.txt validation run: | diff --git a/Cargo.toml b/Cargo.toml index 6b1e8c7..378b558 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,9 @@ name = "conflow" version = "0.1.0" edition = "2021" authors = ["Jonathan D.A. Jewell"] -license = "MIT OR Apache-2.0" +license = "MIT OR AGPL-3.0-or-later" description = "Configuration flow orchestrator for CUE, Nickel, and config validation workflows" -repository = "https://gitlab.com/rhodium-standard/conflow" +repository = "https://gitlab.com/hyperpolymath/conflow" readme = "README.md" keywords = ["configuration", "cue", "nickel", "validation", "pipeline"] categories = ["command-line-utilities", "config", "development-tools"] diff --git a/ECOSYSTEM.scm b/ECOSYSTEM.scm index dce81b0..1b4cc75 100644 --- a/ECOSYSTEM.scm +++ b/ECOSYSTEM.scm @@ -1,8 +1,8 @@ -;; SPDX-License-Identifier: AGPL-3.0-or-later -;; SPDX-FileCopyrightText: 2025 Jonathan D.A. Jewell +;; SPDX-License-Identifier: MIT OR AGPL-3.0-or-later +;; SPDX-FileCopyrightText: 2024-2025 hyperpolymath ;; ECOSYSTEM.scm - Project Ecosystem Relationships ;; conflow -;; Reference: https://github.com/hyperpolymath/ECOSYSTEM.scm +;; Reference: https://gitlab.com/hyperpolymath/ECOSYSTEM.scm (ecosystem (version "1.0.0") diff --git a/META.scm b/META.scm index 3d5d594..bfba28d 100644 --- a/META.scm +++ b/META.scm @@ -1,9 +1,9 @@ -;; SPDX-License-Identifier: AGPL-3.0-or-later -;; SPDX-FileCopyrightText: 2025 Jonathan D.A. Jewell +;; SPDX-License-Identifier: MIT OR AGPL-3.0-or-later +;; SPDX-FileCopyrightText: 2024-2025 hyperpolymath ;;; META.scm — Architecture Decisions and Development Practices ;;; conflow -;;; Reference: https://github.com/hyperpolymath/META.scm +;;; Reference: https://gitlab.com/hyperpolymath/META.scm (define-module (conflow meta) #:export (architecture-decisions @@ -47,7 +47,7 @@ (dependency-scanning . "Dependabot + OSSF Scorecard") (credentials . "Environment variables only, never committed") (input-validation . "Whitelist + schema validation at boundaries") - (license-compliance . "AGPL-3.0-or-later")) + (license-compliance . "MIT OR AGPL-3.0-or-later")) (testing (framework . "language-native") diff --git a/STATE.scm b/STATE.scm index 45637b5..756337c 100644 --- a/STATE.scm +++ b/STATE.scm @@ -4,8 +4,8 @@ ;;; Purpose: Preserve AI conversation context across sessions ;;; Reference: https://github.com/hyperpolymath/state.scm -;; SPDX-License-Identifier: AGPL-3.0-or-later -;; SPDX-FileCopyrightText: 2025 Jonathan D.A. Jewell +;; SPDX-License-Identifier: MIT OR AGPL-3.0-or-later +;; SPDX-FileCopyrightText: 2024-2025 hyperpolymath ;;;============================================================================ ;;; METADATA @@ -15,9 +15,9 @@ '((version . "0.1.0") (schema-version . "1.0") (created . "2025-12-15") - (updated . "2025-12-15") + (updated . "2025-12-17") (project . "conflow") - (repo . "github.com/hyperpolymath/conflow"))) + (repo . "gitlab.com/hyperpolymath/conflow"))) ;;;============================================================================ ;;; PROJECT CONTEXT @@ -27,7 +27,7 @@ '((name . "conflow") (tagline . "Intelligently orchestrate CUE, Nickel, and configuration validation workflows.") (version . "0.1.0") - (license . "AGPL-3.0-or-later") + (license . "MIT OR AGPL-3.0-or-later") (rsr-compliance . "gold-target") (tech-stack @@ -40,19 +40,24 @@ ;;;============================================================================ (define current-position - '((phase . "v0.1 - Initial Setup and RSR Compliance") - (overall-completion . 25) + '((phase . "v0.1.1 - Security Hardening Complete") + (overall-completion . 30) (components ((rsr-compliance ((status . "complete") (completion . 100) - (notes . "SHA-pinned actions, SPDX headers, multi-platform CI"))) + (notes . "SHA-pinned actions, SPDX headers, permissions, multi-platform CI"))) + + (security + ((status . "complete") + (completion . 100) + (notes . "All workflows SHA-pinned, HTTP check fixed, license standardized"))) (documentation ((status . "foundation") - (completion . 30) - (notes . "README exists, META/ECOSYSTEM/STATE.scm added"))) + (completion . 35) + (notes . "README, META/ECOSYSTEM/STATE.scm, updated roadmap"))) (testing ((status . "minimal") @@ -62,13 +67,16 @@ (core-functionality ((status . "in-progress") (completion . 25) - (notes . "Initial implementation underway"))))) + (notes . "Pipeline parsing and execution framework started"))))) (working-features ("RSR-compliant CI/CD pipeline" "Multi-platform mirroring (GitHub, GitLab, Bitbucket)" "SPDX license headers on all files" - "SHA-pinned GitHub Actions")))) + "SHA-pinned GitHub Actions (14 workflows)" + "Security policy enforcement (HTTP blocking, secrets detection)" + "OSSF Scorecard integration" + "CodeQL security analysis")))) ;;;============================================================================ ;;; ROUTE TO MVP @@ -79,30 +87,73 @@ (definition . "Stable release with comprehensive documentation and tests") (milestones - ((v0.2 - ((name . "Core Functionality") + ((v0.1.1 + ((name . "Security Hardening Complete") + (status . "complete") + (items + ("SHA-pinned all GitHub Actions" + "SPDX headers on all workflow files" + "Fixed HTTP URL detection in security-policy.yml" + "Standardized dual license (MIT OR AGPL-3.0-or-later)" + "Added permissions declarations to all workflows" + "Fixed repository URL consistency")))) + + (v0.2 + ((name . "Core Pipeline Execution") + (status . "in-progress") + (items + ("Pipeline definition parsing (.conflow.yaml)" + "DAG-based stage dependency resolution" + "CUE executor implementation" + "Nickel executor implementation" + "Shell executor implementation" + "Basic error handling with miette")))) + + (v0.3 + ((name . "Caching & Watch Mode") (status . "pending") (items - ("Implement primary features" - "Add comprehensive tests" - "Improve documentation")))) + ("BLAKE3-based content hashing" + "Filesystem cache implementation" + "File watching with notify crate" + "Incremental re-execution")))) + + (v0.4 + ((name . "Analysis & Recommendations") + (status . "pending") + (items + ("Config format detection" + "Complexity metrics" + "Tool recommendations engine" + "Migration path suggestions")))) (v0.5 - ((name . "Feature Complete") + ((name . "RSR Integration") + (status . "pending") + (items + ("Compliance checking" + "Badge generation" + "Remediation suggestions" + "Template generation")))) + + (v0.8 + ((name . "Feature Complete Beta") (status . "pending") (items ("All planned features implemented" "Test coverage > 70%" - "API stability")))) + "API stability" + "Performance profiling")))) (v1.0 ((name . "Production Release") (status . "pending") (items - ("Comprehensive test coverage" + ("Comprehensive test coverage (>80%)" "Performance optimization" - "Security audit" - "User documentation complete")))))))) + "Security audit completion" + "User documentation complete" + "Example pipelines library")))))))) ;;;============================================================================ ;;; BLOCKERS & ISSUES @@ -151,6 +202,16 @@ (define session-history '((snapshots + ((date . "2025-12-18") + (session . "security-hardening-review") + (accomplishments + ("SHA-pinned all 14 GitHub workflow files" + "Fixed critical bug in security-policy.yml (http vs https check)" + "Standardized license to MIT OR AGPL-3.0-or-later across all files" + "Added SPDX headers and permissions to all workflows" + "Fixed repository URL inconsistencies" + "Updated roadmap with detailed milestones")) + (notes . "Comprehensive security review and consistency fixes")) ((date . "2025-12-15") (session . "initial-state-creation") (accomplishments @@ -184,11 +245,11 @@ (define state-summary '((project . "conflow") - (version . "0.1.0") - (overall-completion . 25) - (next-milestone . "v0.2 - Core Functionality") + (version . "0.1.1") + (overall-completion . 30) + (next-milestone . "v0.2 - Core Pipeline Execution") (critical-blockers . 0) (high-priority-issues . 0) - (updated . "2025-12-15"))) + (updated . "2025-12-18"))) ;;; End of STATE.scm diff --git a/guix.scm b/guix.scm index e1fbc9c..8cde436 100644 --- a/guix.scm +++ b/guix.scm @@ -1,3 +1,5 @@ +;; SPDX-License-Identifier: MIT OR AGPL-3.0-or-later +;; SPDX-FileCopyrightText: 2024-2025 hyperpolymath ;; conflow - Guix Package Definition ;; Run: guix shell -D -f guix.scm @@ -16,10 +18,10 @@ #:recursive? #t #:select? (git-predicate "."))) (build-system cargo-build-system) - (synopsis "Rust application") - (description "Rust application - part of the RSR ecosystem.") - (home-page "https://github.com/hyperpolymath/conflow") - (license license:agpl3+))) + (synopsis "Configuration Flow Orchestrator") + (description "Intelligently orchestrate CUE, Nickel, and configuration validation workflows.") + (home-page "https://gitlab.com/hyperpolymath/conflow") + (license (list license:expat license:agpl3+)))) ;; Return package for guix shell conflow