@chef/mixlib-install
Copilot Instructions for Mixlib::Install
Install
agr install @chef/mixlib-install --target copilotWrites 1 file into .github/copilot-instructions.md, pinned to git-4ce30714.
- .github/copilot-instructions.md
Document
Copilot Instructions for Mixlib::Install
Project Overview
Mixlib::Install is a library for interacting with Chef Software Inc's software distribution systems. It provides APIs and command-line tools to download Chef products and generate installation scripts for various platforms.
Primary Goal: Support the widest range of Ruby versions possible to ensure compatibility across diverse Chef environments.
Recent Major Changes (v3.13.0 - v3.16.x):
- PR #424: Made package manager (pm) fully optional; removed all client-side pm detection
- Removed
package_managerfromArtifactInfoattributes - Removed
Util.pm_structure_product?,Util.determine_package_manager, andUtil.normalize_platform_for_commercial - Backend routes licensed API + platform requests to
artifact_from_licensed_metadata(metadata endpoint; accurate sha256, no pm) - Added
KNOWN_ARCHITECTURESconstant andpm_structure_response?for runtime response-structure detection (replaces hardcoded product list) - Download URLs use exact user platform (
p=ubuntu,p=el) with nopm=parameter; server derives package manager list-versionsCLI gained--license-id/-Loption andCHEF_LICENSE_KEYenv var supportdownloadCLI checksCHEF_LICENSE_KEYenv var for license_id when not passed explicitly- Trial API:
latest_versionshort-circuits toartifacts_for_version("latest")(trial API does not supportversions/all) - 400/404 responses from metadata endpoint treated as not-found; raises
ArtifactsNotFoundwith license key hint
- Removed
- PR #417: Added chef-ice and inspec-enterprise product support with server-side pm derivation
- Server (omnitruck-service) derives package manager (
pm) from platform automatically; no client-side detection - Client sends platform as-is (
p=$platform); no client-side normalization - Single unified metadata URL for all products:
v,p,pv,m, optionalpm, optionallicense_id -i <package_manager>shell flag and$package_managerPowerShell parameter allow explicit pm override when needed- Added
inspec-enterpriseproduct to product matrix
- Server (omnitruck-service) derives package manager (
- PR #408, #416: Added commercial and trial API support for licensed Chef products
- Implemented license_id parameter for install scripts and API calls
- Added trial API automatic defaults enforcement (stable channel, latest version only with warnings)
- Created
Dist.trial_license?andDist.commercial_license?helper methods
- Install Directory Refactoring: Support for both Omnibus and Habitat package paths
- Renamed
WINDOWS_INSTALL_DIR→OMNIBUS_WINDOWS_INSTALL_DIR,LINUX_INSTALL_DIR→OMNIBUS_LINUX_INSTALL_DIR - Added
HABITAT_WINDOWS_INSTALL_DIR = "hab\\pkgs"andHABITAT_LINUX_INSTALL_DIR = "/hab/pkgs" - Updated
rootandcurrent_versionmethods inlib/mixlib/install.rbto conditionally use Habitat paths for chef-ice - Modified script generators to set appropriate install directories based on product type
- Renamed
- PR #413: Added
list-productsCLI subcommand for product matrix discovery - PR #407: Added Habitat package path detection to generated install scripts
- PR #411: Migrated CI from Buildkite to GitHub Actions with comprehensive test coverage
Ruby Version Support Strategy
Supported Ruby Versions
- Minimum: Ruby 2.6+
- Target Range: Ruby 2.6 through Ruby 3.4+
- Testing Focus: Maintain backward compatibility with Ruby 2.6+ while supporting latest Ruby releases
Critical Compatibility Rules
-
Avoid Modern Ruby Syntax
- NO numbered parameters
_1, _2(Ruby 2.7+) - NO pattern matching (Ruby 2.7+)
- NO endless methods (Ruby 3.0+)
- Use Ruby 2.6-compatible syntax as the baseline
- NO numbered parameters
-
Dependency Version Constraints
- Always use version-conditional dependency constraints in gemspec
- Follow the existing pattern for Ruby version-specific dependencies (see
opensslgem constraints in gemspec) - Consider backward compatibility when adding new dependencies
- Check Gemfile for Ruby version-specific gem constraints before adding dependencies
-
Standard Library Compatibility
- Be cautious with stdlib changes across Ruby versions
- Test with methods available in Ruby 2.6
- Avoid relying on gems that dropped support for Ruby 2.6+
- Ruby 2.6 features that are safe to use:
- Safe navigation operator (
&.) - Squiggly heredoc (
<<~) digmethod on Hash and Arraygrep_von Enumerable- Frozen string literal comment
- Endless ranges:
(1..) Enumerable#chainKernel#then
- Safe navigation operator (
Code Style & Conventions
RuboCop Configuration
- TargetRubyVersion: 2.6 (set in
.rubocop.yml) - Note: RuboCop targets 2.6 to match the minimum supported Ruby version
- Uses
chefstylegem version ~> 0.4.0 - Run style checks:
bundle exec rake style
Code Formatting
- Indentation: 2 spaces (defined in
.editorconfig) - Line Endings: Unix-style LF
- Charset: UTF-8
- Trailing Whitespace: Remove (trim_trailing_whitespace: true)
- Final Newline: Always include
- Emojis: Never use emojis in any code, comments, output messages, test assertions, or documentation
File Headers
All Ruby files should include the Apache 2.0 license header:
#
# Author:: [Author Name] (<email@chef.io>)
# Copyright:: Copyright (c) [year] Chef Software, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# ...
Architecture & Structure
Core Components
-
Mixlib::Install (
lib/mixlib/install.rb)- Main entry point for the library
- Provides
artifact_info,available_versions,install_command,download_artifactmethods - Delegates to Backend for API interactions
-
Options (
lib/mixlib/install/options.rb)- Validates and normalizes user input
- Supports EXTRA_PRODUCTS_FILE environment variable for custom products
- Key options: channel, product_name, product_version, platform, platform_version, architecture, license_id
- license_id: Enables commercial/trial API access for licensed Chef products
- Trial API Enforcement: Automatically defaults channel to :stable and product_version to :latest when trial license detected
- Uses
enforce_trial_api_defaults!method during initialization to apply restrictions - Emits warnings to stderr when defaults are applied
-
Product Matrix (
lib/mixlib/install/product_matrix.rb)- DSL for defining product metadata
- Extensible via EXTRA_PRODUCTS_FILE
- Run
bundle exec rake matrixto update PRODUCT_MATRIX.md after changes
-
Backend (
lib/mixlib/install/backend/)- Package Router backend for Chef's package API
- Handles API communication with packages.chef.io
-
Generators (
lib/mixlib/install/generator/)- Bourne shell (install.sh) generator with Content-Disposition header support
- PowerShell (install.ps1) generator with JSON API response parsing
- Supports proxy configuration, download_url_override, and license_id
- Commercial/Trial API Support: When license_id is provided, uses specialized download endpoints
- Trial API:
https://chefdownload-trial.chef.io(for license IDs starting withtrial-) - Commercial API:
https://chefdownload-commercial.chef.io(for other license IDs) - Returns JSON responses instead of text format
- Uses Content-Disposition headers for filename extraction
- Implements temp file download approach with multiple filename extraction methods
- Trial API:
-
Artifact Info (
lib/mixlib/install/artifact_info.rb)- Represents package metadata
- Includes platform, version, URL, checksum, license info
Supported Architectures
- aarch64, armv7l, i386, powerpc, ppc64, ppc64le, s390x, sparc, universal, x86_64
Supported Channels
- :stable, :current, :unstable
Testing
Test Structure
- Unit Tests:
spec/unit/**/*_spec.rb - Functional Tests:
spec/functional/**/*_spec.rb - Acceptance Tests:
acceptance/**/*
Running Tests
bundle exec rake unit # Unit tests only
bundle exec rake functional # Functional tests only
bundle exec rake # All tests (default)
VCR for HTTP Mocking
- Uses VCR gem for recording/replaying HTTP interactions
- Cassettes stored in
spec/support/ - To update cassettes, see instructions in
spec/spec_helper.rb - Functional tests disable VCR to test live interactions
Gemspec vs Gemfile Dependencies
Gemspec (mixlib-install.gemspec):
- Runtime dependencies only
- Minimal dependencies: mixlib-shellout, mixlib-versioning, thor
- No version constraints in latest version (dependencies have their own compatibility handling)
Gemfile:
- Development and test dependencies
- Ruby version-specific constraints for test tools
- Includes chefstyle for linting (~> 0.4.0)
- VCR for HTTP mocking in tests
Ruby Version-Specific Test Dependencies
The Gemfile contains careful version constraints for test dependencies based on RUBY_VERSION:
- Ruby < 2.6: Specific version pins for chef-utils, climate_control, mixlib-shellout, vcr
- Ruby 2.6-2.7: Different constraint ranges
- Ruby 2.7+: Loosened constraints
- Ruby 3.2+: Minimal constraints
When adding test dependencies, follow this pattern.
Development Guidelines
Adding New Features
-
Product Addition
- Update
lib/mixlib/install/product_matrix.rbwith DSL definition - Run
bundle exec rake matrixto update documentation - Add tests in
spec/unit/mixlib/install/product_spec.rb
- Update
-
Platform Support
- Update
lib/mixlib/install/options.rbSUPPORTED_ARCHITECTURES if needed - Add platform detection logic in
lib/mixlib/install/util.rb - Update install script generators if platform-specific logic needed
- Update
-
API Changes
- Maintain backward compatibility
- Add deprecation warnings before removing features
- Update README.md with examples
- Add/update tests
Version Management
- Version defined in
lib/mixlib/install/version.rb - Follow semantic versioning
- Expeditor handles automated version bumps via labels:
- "Expeditor: Bump Version Minor"
- "Expeditor: Bump Version Major"
Dependency Management
Adding Dependencies to Gemspec
- Consider minimum Ruby version compatibility
- Use version constraints with Ruby version conditionals if needed
- Example pattern (from gemspec):
if RUBY_VERSION < "2.7.0"
spec.add_dependency "openssl", ">= 3.1.2", "< 3.2.0"
elsif RUBY_VERSION < "3.3.0"
spec.add_dependency "openssl", ">= 3.1.2"
# ... etc
end
Adding Test Dependencies to Gemfile
- Group dependencies by Ruby version ranges
- Pin versions for older Ruby (< 2.6) to ensure compatibility
- Test locally with multiple Ruby versions if possible
OpenSSL Dependency Notes
The gemspec includes special handling for the openssl gem due to CRL checking issues:
- Different version constraints based on Ruby version
- This pattern should be followed for other security-critical dependencies
CLI Tool
Command: mixlib-install
- Executable:
bin/mixlib-install - Entry point:
lib/mixlib/install/cli.rb - Uses Thor for CLI framework
- Run
mixlib-install helpfor available commands
Common Commands
mixlib-install download chef # Download latest stable chef
mixlib-install download chef-ice -L <license_id> # Download licensed product
mixlib-install list-products # List all available products (added in v3.14.0)
mixlib-install list-versions chef stable # List versions for omnitruck product
mixlib-install list-versions chef-ice stable -L <license_id> # List versions for licensed product
mixlib-install help # Show all commands
CHEF_LICENSE_KEY environment variable can be used instead of -L for all commands.
Available Subcommands
download- Download a Chef Software product (accepts-L <license_id>orCHEF_LICENSE_KEY)list-products- Display all available products from the product matrixlist-versions- List available versions for a product (accepts-L <license_id>orCHEF_LICENSE_KEYfor licensed products)help- Display help information
Generated Script Parameters
When using install_sh() or install_ps1() methods or CLI-generated scripts:
-b <url>/-base_api_url <url>(shell): Override API endpoint-L <id>/-license_id <id>(shell): Provide license ID for commercial/trial API-l <id>(PowerShell): Provide license ID for commercial/trial API- Scripts automatically detect correct API endpoint based on license_id prefix if base URL not provided
Platform Version Compatibility Mode
The library includes sophisticated platform version compatibility logic:
- Automatically maps to earlier platform versions when exact match not available
- Example: Ubuntu 15.04 → Ubuntu 14.04 compatibility
- Controlled by
platform_version_compatibility_modeoption
Install Script Generation
Bourne Shell (install.sh)
- Supports: http_proxy, https_proxy, ftp_proxy, no_proxy
- Platform detection for Linux/Unix systems
- Generated via
lib/mixlib/install/generator/bourne.rb - API Endpoint Selection: Uses
base_api_urlparameter to determine endpoint:- If
base_api_urlis empty andlicense_idis provided:- Trial API:
https://chefdownload-trial.chef.io(fortrial-*prefixes) - Commercial API:
https://chefdownload-commercial.chef.io(for other license IDs)
- Trial API:
- If
base_api_urlis empty and nolicense_id: Omnitruck APIhttps://omnitruck.chef.io - If
base_api_urlis set: Uses the provided URL (allows override)
- If
- Content-Disposition Support: When
license_idis provided:- Downloads to temp file:
chef-download-temp.$$ - Extracts filename from HTTP response headers (3 methods):
- Content-Disposition header:
attachment; filename="..." - Location redirect header: Extract from redirect URL
- URL pattern matching: Search for
.rpm|.deb|.pkg|.msi|.dmgpatterns
- Content-Disposition header:
- Fallback: Constructs filename from platform metadata if extraction fails
- Renames temp file to extracted/constructed filename
- Works with all download methods: wget, curl, fetch, perl, python
- Downloads to temp file:
- Package Manager Override (
-iflag): Optional flag for explicit pm control- Default: omitted — server derives
pmfrom platform automatically - When
-i <pm>is passed, appends&pm=<value>to the metadata URL - No client-side
determine_package_manager()ornormalize_platform_name()functions - Single unified metadata URL for all products, including chef-ice and inspec-enterprise
- Default: omitted — server derives
PowerShell (install.ps1)
- Supports: http_proxy
- Windows platform support
- TLS negotiation for older .NET versions
- Generated via
lib/mixlib/install/generator/powershell.rb - API Endpoint Selection: Uses
base_server_uriparameter to determine endpoint:- If
base_server_uriis empty andlicense_idis provided:- Trial API:
https://chefdownload-trial.chef.io(fortrial-*prefixes) - Commercial API:
https://chefdownload-commercial.chef.io(for other license IDs, includingfree-*)
- Trial API:
- If
base_server_uriis empty and nolicense_id: Omnitruck APIhttps://omnitruck.chef.io - If
base_server_uriis set: Uses the provided URL (allows override)
- If
- JSON API Response: When
license_idis provided:- Parses JSON responses with
ConvertFrom-Json - Extracts
urlandsha256from JSON object - Automatically routes to trial or commercial API based on license_id prefix
- Parses JSON responses with
- Package Manager Override (
$package_manager): Optional parameter for explicit pm control- Default: empty — server derives
pmfrom platform automatically - When non-empty, appends
&pm=<value>to the metadata URL - No product-specific conditional URL branches; single unified URL for all products
- Default: empty — server derives
Script Options
download_url_override: Direct URL instead of API lookupchecksum: SHA256 for verificationinstall_strategy: "once" to skip if already installedlicense_id: License ID for commercial/trial API access (format:trial-*for trial API, or any other value includingfree-*for commercial API)base_api_url(shell): Override API endpoint (optional, auto-detected from license_id if not provided)base_server_uri(PowerShell): Override API endpoint (optional, auto-detected from license_id if not provided)-i <pm>/$package_manager: Explicit package manager override (e.g.msi,zip). Omit to let the server derive it from platform. Appends&pm=<value>to the metadata URL when set.
API Usage Patterns
Basic Usage
options = {
channel: :current,
product_name: 'chef',
product_version: :latest,
platform: 'mac_os_x',
platform_version: '10.15',
architecture: 'x86_64'
}
artifact = Mixlib::Install.new(options).artifact_info
Proxy Configuration
Relies on OpenURI environment variables:
- http_proxy, https_proxy, ftp_proxy, no_proxy
Product Extension System
Users can extend with custom products via EXTRA_PRODUCTS_FILE environment variable:
# custom_products.rb
product "cinc" do
product_name "Cinc Infra Client"
package_name "cinc-client"
api_url "https://packages.cinc.sh"
end
When implementing features, ensure this extensibility is maintained.
GitHub Workflows & CI
- Uses Expeditor for release automation
- Verify pipeline in
.expeditor/verify.pipeline.yml - Linux tests:
.expeditor/run_linux_tests.sh - Windows tests:
.expeditor/run_windows_tests.ps1
Commercial and Trial API Integration
Overview
Mixlib::Install supports Chef's commercial and trial licensing APIs, which provide authenticated access to Chef products for licensed customers.
API Endpoints
- Trial API:
https://chefdownload-trial.chef.io- Used when
license_idstarts withtrial- - Returns JSON responses with download URLs
- Restrictions: Only
stablechannel andlatestversion supported - Defaults are automatically enforced with warnings
- Used when
- Commercial API:
https://chefdownload-commercial.chef.io- Used for all other license IDs (including
free-prefix) - Returns JSON responses with download URLs
- No restrictions on channels or versions
- Used for all other license IDs (including
- Traditional Omnitruck:
https://omnitruck.chef.io- Used when no
license_idis provided - Returns text-based metadata responses
- Used when no
Response Format Differences
- Commercial/Trial APIs: JSON format
{ "url": "https://...", "sha256": "abc123..." } - Omnitruck API: Text format
url\thttp://... sha256\tabc123...
Error Handling for Trial API Restrictions
The backend (lib/mixlib/install/backend/package_router.rb) includes enhanced error handling:
- Catches
Net::HTTPClientErrorandNet::HTTPServerErrorduring API calls - Provides helpful error messages when trial API restrictions are violated:
- If trial license is detected but non-compliant settings are used (channel != :stable or version != :latest)
- Error message includes current settings and reminds user of trial API limitations
- Re-raises original error for other failure scenarios
License ID Detection Helper Methods (lib/mixlib/install/dist.rb)
require 'mixlib/install/dist'
# Check if license_id indicates trial API usage
Mixlib::Install::Dist.trial_license?('free-trial-123') # => false
Mixlib::Install::Dist.trial_license?('trial-abc-456') # => true
Mixlib::Install::Dist.trial_license?('commercial-xyz') # => false
# Check if license_id indicates commercial API usage
Mixlib::Install::Dist.commercial_license?('commercial-xyz') # => true
Mixlib::Install::Dist.commercial_license?('free-trial-123') # => true
Trial License Detection Logic:
- Returns
trueif license_id starts withtrial- - Returns
falsefor nil, empty string, or other prefixes (includingfree-)
Commercial License Detection Logic:
- Returns
trueif license_id is present and NOT a trial license - Returns
falsefor nil, empty string, or trial licenses
Content-Disposition Header Handling
Commercial and trial APIs return endpoint URLs that use HTTP Content-Disposition headers to specify the actual filename, rather than including the filename in the URL path.
Implementation Details:
- Detection:
use_content_disposition="true"whenlicense_idis present - Download Strategy: Use temp file with process ID suffix:
chef-download-temp.$$ - Filename Extraction (3 methods, attempted in order):
- Parse
Content-Dispositionheader:filename="chef-18.8.54-1.el9.x86_64.rpm" - Parse
Locationredirect header: Extract filename from redirect URL - Pattern matching: Search stderr output for
.rpm|.deb|.pkg|.msi|.dmgextensions
- Parse
- Fallback Construction: Build filename from platform metadata if extraction fails
- File Rename: Move temp file to final location with extracted/constructed filename
Cross-Platform Compatibility: This approach works with all download methods:
wget(with--content-dispositionflag as secondary approach)curl(with-O -Jflags as secondary approach)fetch(FreeBSD)perl(LWP::Simple)python(urllib2)
Testing Commercial/Trial API Features
When adding or modifying commercial/trial API functionality:
- Test with
license_idstarting withtrial-(trial API) - Test with
license_idstarting withfree-(commercial API) - Test with standard license ID format (commercial API)
- Verify JSON parsing in both Bourne shell (sed) and PowerShell (ConvertFrom-Json)
- Test filename extraction with various response header formats
- Verify fallback filename construction for each platform type
- Test chef-ice product downloads with exact platform parameter (
p=ubuntu,p=el,p=windows) - Verify no
pm=parameter appears in download URLs (server derives from platform) - Test trial API automatic defaults enforcement (stable channel, latest version)
Test Patterns for Chef-ICE and Trial API
Key test patterns to follow (see spec/unit/mixlib/install/generator_spec.rb for examples):
Chef-ICE Shell Script Tests:
context "chef-ice with commercial API" do
let(:add_options) do
{
product_name: "chef-ice",
license_id: "test-license-key-123",
}
end
it "constructs unified metadata URL without client-side pm" do
expect(install_script).to include("metadata?")
expect(install_script).not_to include("p=linux")
expect(install_script).not_to include("determine_package_manager")
end
it "supports optional package_manager override via -i flag" do
expect(install_script).to include("package_manager")
end
end
Chef-ICE PowerShell Tests:
context "chef-ice with commercial API for PowerShell" do
let(:add_options) do
{
product_name: "chef-ice",
shell_type: :ps1,
license_id: "test-license-key-123",
}
end
it "includes simplified parameters for chef-ice on Windows" do
expect(install_script).to include('$platform_param = "windows"')
expect(install_script).to include('$package_manager = "msi"')
end
it "constructs chef-ice metadata URL with m, p, pm parameters" do
expect(install_script).to include('$metadata_url = "$base_server_uri/$channel/$project/metadata?license_id=$license_id&v=$version&m=$architecture&p=$platform_param&pm=$package_manager"')
end
end
Trial API Enforcement Tests:
it "defaults to stable channel when current channel is specified" do
expect do
mi = Mixlib::Install.new(product_name: "chef", channel: :current, license_id: "trial-abc-123")
expect(mi.options.channel).to eq :stable
end.to output(/WARNING: Trial API only supports 'stable' channel/).to_stderr
end
it "defaults to latest version when specific version is specified" do
expect do
mi = Mixlib::Install.new(product_name: "chef", product_version: "15.0.0", license_id: "trial-abc-123")
expect(mi.options.product_version).to eq :latest
end.to output(/WARNING: Trial API only supports 'latest' version/).to_stderr
end
Chef-ICE Product Support
The chef-ice product (Chef Infra Client Enterprise, Chef 19+) requires special handling:
Key Characteristics:
- Product Name:
chef-ice - Package Name:
chef-ice - Minimum Version: Chef 19.x
- API Compatibility: Works with both commercial and trial APIs
- URL Parameters: Uses the same
p,pv,m,v,license_idformat as all other licensed products; server derives pm - Install Directories: Uses Habitat package paths instead of Omnibus paths
Install Directory Constants (lib/mixlib/install/dist.rb):
Chef products use different install directory structures depending on whether they're packaged with Omnibus or Habitat:
Omnibus Products (chef, chefdk, etc.):
- Windows:
$env:systemdrive\opscode\{product} - Linux:
/opt/{product} - Constants:
OMNIBUS_WINDOWS_INSTALL_DIR,OMNIBUS_LINUX_INSTALL_DIR
Habitat Products (chef-ice):
- Windows:
$env:systemdrive\hab\pkgs\chef\chef-infra-client\*\* - Linux:
/hab/pkgs/chef/chef-infra-client/*/* - Constants:
HABITAT_WINDOWS_INSTALL_DIR,HABITAT_LINUX_INSTALL_DIR
Implementation Details:
OMNIBUS_WINDOWS_INSTALL_DIR = "opscode"- Traditional Chef install base directory for WindowsOMNIBUS_LINUX_INSTALL_DIR = "/opt"- Traditional Chef install base directory for LinuxHABITAT_WINDOWS_INSTALL_DIR = "hab\\pkgs"- Habitat package directory for WindowsHABITAT_LINUX_INSTALL_DIR = "/hab/pkgs"- Habitat package directory for Linux
Usage in Code:
lib/mixlib/install.rb:rootandcurrent_versionmethods check product name and use appropriate constantslib/mixlib/install/script_generator.rb: Sets@rootbased on product type after initializationlib/mixlib/install/generator/base.rb: Conditionally setscontext[:windows_dir]for chef-ice
The wildcard paths (*/*) in Habitat directories allow matching any version/release combination of the package.
URL Parameter Differences:
All licensed API products use the same URL parameter format. The server derives pm from the exact platform name automatically.
All Licensed API Products (chef, chef-ice, inspec-enterprise, etc.):
Download: ?p={platform}&pv={platform_version}&m={machine}&v={version}&license_id={id}
Metadata: ?v={version}&p={platform}&pv={platform_version}&m={machine}&license_id={id}
Send the exact platform name as-is (e.g. ubuntu, el, mac_os_x); do not normalize or add pm=.
Platform Normalization (Util.normalize_platform_for_commercial):
Removed in PR #424. The server now derives the package manager from the exact platform name; no client-side normalization is needed.
Package Manager Detection (Util.determine_package_manager):
Removed in PR #424. The server now derives the package manager from the exact platform name; no client-side pm detection is needed.
Implementation Locations:
- Backend Logic:
lib/mixlib/install/backend/package_router.rbavailable_artifacts: routes toartifact_from_licensed_metadatawhen licensed API + platform availableartifact_from_licensed_metadata: calls metadata endpoint withv,p,pv,m; no pm; handles 400/404 cleanlypm_structure_response?: detects PM-structure API responses at runtime viaKNOWN_ARCHITECTURESconstantcreate_artifact: builds download URL with exact user platform; no pm parameter
- Shell Script:
lib/mixlib/install/generator/bourne/scripts/fetch_metadata.sh- Unified metadata URL for all products; optional
-i <pm>flag for explicit override only
- Unified metadata URL for all products; optional
- PowerShell Script:
lib/mixlib/install/generator/powershell/scripts/get_project_metadata.ps1- Unified metadata URL for all products; optional
$package_managerparameter for explicit override only
- Unified metadata URL for all products; optional
- Root Directory Logic:
lib/mixlib/install.rbandlib/mixlib/install/script_generator.rb- Methods check product name and conditionally use Habitat paths
rootmethod returns appropriate install directory pathcurrent_versionmethod uses correct version-manifest.json path
Example Usage:
options = {
product_name: 'chef-ice',
channel: :stable,
product_version: :latest,
platform: 'ubuntu',
platform_version: '20.04',
architecture: 'x86_64',
license_id: 'trial-abc-123'
}
artifact = Mixlib::Install.new(options).artifact_info
# URL: https://chefdownload-trial.chef.io/stable/chef-ice/download?p=ubuntu&pv=20.04&m=x86_64&v=19.1.151&license_id=trial-abc-123
Common Pitfalls to Avoid
- Don't use Ruby 2.7+ features - Always consider Ruby 2.6 compatibility
- Don't assume gem availability - Check version constraints in Gemfile first
- Don't break the Product Matrix DSL - It's critical for product definitions
- Don't skip
rake matrix- Must run after modifying product_matrix.rb - Don't hardcode URLs - Use product definitions and API lookups
- Don't ignore platform compatibility - Test across platforms when possible
- Don't add dependencies without version constraints - Especially for Ruby 2.6+ support
- Don't assume filename in URL - Commercial/trial APIs use Content-Disposition headers
- Don't break temp file download approach - Required for license_id support across all download methods
- Don't add pm= to download URLs - The server derives package manager from the platform name; omit pm entirely
- Don't bypass trial API defaults - Trial licenses must use stable channel and latest version
- Don't use emojis - Never use emojis in code, comments, output messages, or documentation
Common Issues and Solutions
Chef-ICE Installation Issues:
- Use exact platform name (
ubuntu,el,windows) inp=parameter; no normalization needed - Check that Habitat install directories are used (not Omnibus paths)
- Do not add
pm=to download or metadata URLs; the server derives it from the platform - For
list-versionson commercial-only products, provide-L <license_id>or setCHEF_LICENSE_KEY
Trial API Restrictions:
- Trial licenses automatically default to stable channel with warning
- Trial licenses automatically default to latest version with warning
- Users cannot override these defaults for trial API
- Commercial licenses have no such restrictions
Content-Disposition Filename Extraction:
- If filename extraction fails, fallback construction should work
- Test with multiple download tools (wget, curl, fetch, perl, python)
- Verify temp file approach doesn't break existing functionality
- Check that filename has correct extension for platform (.rpm, .deb, .msi, etc.)
API Endpoint Selection Issues:
- Ensure
base_api_url/base_server_uriconditional logic checks for empty/unset (not inverted) - Shell scripts: Use
[ -z "$base_api_url" ]to check if empty - PowerShell scripts: Use
[string]::IsNullOrEmpty($base_server_uri)to check if empty - When set by user, respect the provided endpoint URL
- When unset, automatically determine based on license_id presence and prefix
Documentation Requirements
When making changes:
- Update README.md with API examples if public interface changes
- Update CHANGELOG.md (handled by Expeditor)
- Run
rake matrixif products changed - Add code comments for complex compatibility logic
- Document Ruby version requirements for new features
Performance Considerations
- Minimize external gem dependencies
- Cache HTTP responses appropriately (VCR in tests)
- Efficient platform detection (runs on every install)
- Keep install scripts small and fast
Security Considerations
- Checksum Verification: Always provide/verify SHA256 checksums
- HTTPS: Use secure connections to packages.chef.io
- OpenSSL: Maintain up-to-date openssl gem constraints (see gemspec)
- Proxy Support: Respect proxy settings in secure environments
- License Content: Handle license_content securely (may contain sensitive info)
Release Process
- Merge PR to main branch
- Expeditor automatically bumps version (unless skip label)
- Expeditor builds gem
- Manual promotion triggers RubyGems publish
- GitHub release created with version tag (v{{version}})
Getting Help
- Slack: #chef-found-notify (Chef Software internal)
- GitHub Issues: Response time maximum 14 days
- Pull Requests: Response time maximum 14 days
- Project State: Active (see README.md)
Quick Reference
Key Files
lib/mixlib/install.rb- Main entry pointlib/mixlib/install/options.rb- Option validationlib/mixlib/install/product_matrix.rb- Product definitionslib/mixlib/install/version.rb- Version constantmixlib-install.gemspec- Gem specification with dependency constraintsGemfile- Development/test dependencies with Ruby version logic
Key Commands
bundle exec rake- Run all testsbundle exec rake matrix- Update product matrix docsbundle exec rake style- Run style checksbundle exec rake console- Interactive console with mixlib-install loaded
Environment Variables
EXTRA_PRODUCTS_FILE- Path to custom product definitionshttp_proxy,https_proxy,ftp_proxy,no_proxy- Proxy configurationCHEF_LICENSE_KEY- Fallback license ID for install scripts (if not provided via parameter)
Quick Reference: Chef-ICE vs Standard Products
| Aspect | Standard Products (chef, chefdk, etc.) | Chef-ICE Product |
|---|---|---|
| Package System | Omnibus | Habitat |
| Install Dir (Windows) | C:\opscode\<product> | C:\hab\pkgs\chef\chef-infra-client\*\* |
| Install Dir (Linux) | /opt/<product> | /hab/pkgs/chef/chef-infra-client/*/* |
| URL Parameters | ?p=<platform>&pv=<version>&m=<arch>&v=<version>&license_id=<id> | ?v=<version>&license_id=<id>&m=<arch>&p=<normalized>&pm=<manager> |
| Platform Values | Specific (ubuntu, el, centos, etc.) | Normalized (linux, macos, windows, unix) |
| Requires PM Param | No | Yes (rpm, deb, msi, dmg, tar) |
| Min Version | Varies by product | Chef 19+ |
Quick Reference: License Types
| License Type | ID Format | API Endpoint | Channel | Version | Auto-Defaults |
|---|---|---|---|---|---|
| Trial | trial-* | https://chefdownload-trial.chef.io | stable only | latest only | Yes (with warnings) |
| Commercial | Any other format (including free-*) | https://chefdownload-commercial.chef.io | Any | Any | No |
| Open Source | None | https://omnitruck.chef.io | Any | Any | No |
Remember: When in doubt about Ruby version compatibility, check the Gemfile and gemspec for version-specific patterns, and test with Ruby 2.6+ when possible. The goal is maximum compatibility (Ruby 2.6+) without sacrificing functionality.
For chef-ice products, always verify that platform normalization and package manager detection work correctly for the target platform before deploying changes.
Ruby 2.6+ Feature Reference
Safe to Use (Ruby 2.6+)
- Safe navigation operator:
object&.method - Squiggly heredoc:
<<~TEXT Hash#dig,Array#digEnumerable#grep_vHash#fetch_valuesHash#to_proc- Frozen string literal pragma:
# frozen_string_literal: true - Endless ranges:
(1..) Enumerable#chainKernel#thenInteger#digitsComparable#clampString#match?,Regexp#match?- Multiple assignment in conditionals
yield_self/thenrescuein blocks withoutbegin
Avoid (Ruby 2.7+)
- Numbered parameters:
_1,_2 - Pattern matching
Enumerable#filter_mapEnumerable#tally- Method reference operator:
.:
Trust
Not scanned yet. Artifacts are graded after they are crawled, so a recently discovered one may have no result for a while.
Versions
git-4ce3071464b52026-08-04