stout 0.2.0

A fast, Rust-based Homebrew-compatible package manager
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
# Enterprise Deployment Guide

stout is designed for enterprise environments with features for private hosting, CI/CD integration, air-gapped installations, and compliance requirements.

## Table of Contents

- [Use Cases]#use-cases
- [Private Index Hosting]#private-index-hosting
- [Custom Signing Keys]#custom-signing-keys
- [CI/CD Integration]#cicd-integration
- [Air-Gapped Installations]#air-gapped-installations
- [Multi-Prefix Environments]#multi-prefix-environments
- [Audit Logging]#audit-logging
- [Compliance]#compliance
- [Performance at Scale]#performance-at-scale

## Use Cases

### Internal Development Teams

- **Standardized tooling**: Ensure all developers have the same package versions
- **Reproducible builds**: Lock files guarantee consistent environments
- **Fast onboarding**: New developers get productive in minutes

### CI/CD Pipelines

- **Cached dependencies**: Offline mirrors eliminate network latency
- **Deterministic builds**: Pinned versions prevent "works on my machine"
- **Parallel execution**: Multiple jobs share the same package cache

### Regulated Industries

- **Audit trails**: Track every package installation
- **Approved packages**: Curate allowed packages via private index
- **Vulnerability management**: Automated scanning with `stout audit`

### Air-Gapped Environments

- **Offline operation**: Full functionality without internet access
- **Controlled updates**: Manual mirror synchronization
- **Security compliance**: No external network dependencies

## Private Index Hosting

Host your own stout index for complete control over available packages.

### Option 1: GitHub (Private Repository)

The simplest approach for teams already using GitHub:

```bash
# Fork the stout-index repository to your organization
# Make it private
# Update stout configuration
```

**~/.stout/config.toml:**
```toml
[index]
base_url = "https://raw.githubusercontent.com/YOUR_ORG/stout-index/main"
```

For authentication, set a GitHub token:
```bash
export STOUT_GITHUB_TOKEN="ghp_xxxxx"
```

### Option 2: Static File Server

Host the index on any web server (nginx, Apache, S3, etc.):

```bash
# Sync the index locally
cd /path/to/index
./scripts/sync_all.sh

# Structure:
# /path/to/index/
# ├── manifest.json
# ├── index.db.zst
# ├── formulas/
# │   ├── manifest.json
# │   ├── index.db.zst
# │   └── data/
# │       ├── a/
# │       │   └── ack.json.zst
# │       └── ...
# └── casks/
#     └── ...
```

**nginx configuration:**
```nginx
server {
    listen 443 ssl;
    server_name stout.internal.company.com;

    ssl_certificate /etc/ssl/stout.crt;
    ssl_certificate_key /etc/ssl/stout.key;

    root /var/www/stout-index;

    location / {
        autoindex off;
        add_header Cache-Control "public, max-age=300";
    }

    # Enable gzip for JSON files
    gzip on;
    gzip_types application/json;
}
```

### Option 3: S3 / Cloud Storage

For AWS S3:
```bash
# Sync index to S3
aws s3 sync /path/to/index s3://company-stout-index/ \
    --content-encoding zstd \
    --cache-control "max-age=300"

# Configure CloudFront for HTTPS
```

**~/.stout/config.toml:**
```toml
[index]
base_url = "https://stout.company.cloudfront.net"
```

### Curating Packages

Create a custom index with only approved packages:

```python
#!/usr/bin/env python3
"""Sync only approved formulas to private index."""

import json
from pathlib import Path

APPROVED_FORMULAS = [
    "git", "curl", "jq", "yq", "python@3.11", "node@20",
    "go", "rust", "cmake", "make", "gcc",
    # Add your approved packages
]

def filter_index(source_dir: Path, dest_dir: Path):
    """Copy only approved formulas to destination."""
    for formula in APPROVED_FORMULAS:
        first_char = formula[0]
        src = source_dir / "formulas" / "data" / first_char / f"{formula}.json.zst"
        if src.exists():
            dst = dest_dir / "formulas" / "data" / first_char / f"{formula}.json.zst"
            dst.parent.mkdir(parents=True, exist_ok=True)
            shutil.copy(src, dst)

    # Rebuild the SQLite index with only approved formulas
    # (Use the sync scripts with a filter)
```

## Custom Signing Keys

Generate and use your own signing keys for complete trust chain control.

### Generate a Keypair

```bash
cd /path/to/stout-index/scripts

# Install dependencies
uv sync

# Generate new keypair
uv run python sign_index.py generate --output ../keys

# Output:
# Generated keypair:
#   Private key: ../keys/stout-index.key
#   Public key:  ../keys/stout-index.pub
#
# Public key (hex): abc123...
```

### Configure stout to Trust Your Key

**Option 1: Replace the default key** (requires building from source)

Edit `crates/stout-index/src/signature.rs`:
```rust
pub const DEFAULT_PUBLIC_KEY_HEX: &str = "YOUR_PUBLIC_KEY_HEX";
```

**Option 2: Add as additional trusted key** (runtime configuration)

**~/.stout/config.toml:**
```toml
[security]
additional_trusted_keys = [
    "YOUR_PUBLIC_KEY_HEX"
]
```

### Sign Your Index

```bash
# Using key file
uv run python sign_index.py sign \
    --key ./keys/stout-index.key \
    --index-dir /path/to/index

# Using environment variable (for CI)
export STOUT_SIGNING_KEY="private_key_hex"
uv run python sign_index.py sign \
    --key '$STOUT_SIGNING_KEY' \
    --index-dir /path/to/index
```

### Key Management Best Practices

1. **Store private keys securely**: Use HashiCorp Vault, AWS Secrets Manager, or similar
2. **Rotate keys periodically**: Add new keys to `additional_trusted_keys` before rotating
3. **Backup keys**: Losing the private key requires re-signing all indexes
4. **Audit key usage**: Log all signing operations

## CI/CD Integration

### GitHub Actions

```yaml
name: Build with stout

on: [push, pull_request]

jobs:
  build:
    runs-on: macos-latest  # or ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Install stout
        run: |
          curl -fsSL https://raw.githubusercontent.com/neul-labs/stout/main/install.sh | bash
          echo "$HOME/.local/bin" >> $GITHUB_PATH

      - name: Cache stout packages
        uses: actions/cache@v4
        with:
          path: |
            ~/.stout/downloads
            ~/.stout/cache
          key: stout-${{ runner.os }}-${{ hashFiles('Brewfile.lock') }}
          restore-keys: |
            stout-${{ runner.os }}-

      - name: Install dependencies
        run: |
          stout update
          stout bundle install

      - name: Build
        run: make build
```

### GitLab CI

```yaml
stages:
  - setup
  - build

variables:
  STOUT_CACHE_DIR: ${CI_PROJECT_DIR}/.stout-cache

install-deps:
  stage: setup
  image: ubuntu:22.04
  cache:
    key: stout-${CI_COMMIT_REF_SLUG}
    paths:
      - .stout-cache/
  script:
    - curl -fsSL https://raw.githubusercontent.com/neul-labs/stout/main/install.sh | bash
    - export PATH="$HOME/.local/bin:$PATH"
    - stout update
    - stout bundle install
  artifacts:
    paths:
      - /opt/homebrew/Cellar/

build:
  stage: build
  needs: [install-deps]
  script:
    - make build
```

### Jenkins

```groovy
pipeline {
    agent any

    environment {
        STOUT_CACHE = "${WORKSPACE}/.stout-cache"
    }

    stages {
        stage('Setup') {
            steps {
                sh '''
                    curl -fsSL https://raw.githubusercontent.com/neul-labs/stout/main/install.sh | bash
                    export PATH="$HOME/.local/bin:$PATH"
                    stout update
                    stout bundle install
                '''
            }
        }

        stage('Build') {
            steps {
                sh 'make build'
            }
        }
    }

    post {
        always {
            // Cache cleanup
            sh 'stout cleanup --prune=7'
        }
    }
}
```

### Brewfile for CI

Create a `Brewfile` for reproducible dependencies:

```ruby
# Brewfile
# Build tools
brew "cmake"
brew "make"
brew "ninja"

# Languages
brew "python@3.11"
brew "node@20"
brew "go"
brew "rust"

# Utilities
brew "jq"
brew "yq"
brew "curl"
brew "git"

# Testing
brew "shellcheck"
brew "hadolint"
```

### Lock Files

Generate and commit lock files for reproducibility:

```bash
# Generate lock file from installed packages
stout lock generate

# Install exact versions from lock file
stout lock install

# Verify lock file matches installed
stout lock verify
```

**Brewfile.lock format:**
```json
{
  "generated_at": "2024-11-27T12:00:00Z",
  "stout_version": "0.1.0",
  "packages": {
    "jq": {
      "version": "1.7.1",
      "bottle_sha256": "abc123...",
      "dependencies": ["oniguruma"]
    }
  }
}
```

## Air-Gapped Installations

For environments without internet access.

### Create an Offline Mirror

```bash
# Create mirror with specific packages
stout mirror create /path/to/mirror jq curl git python@3.11

# Include all dependencies
stout mirror create /path/to/mirror --with-deps jq curl

# Mirror everything in a Brewfile
stout mirror create /path/to/mirror --from-brewfile ./Brewfile

# Include casks
stout mirror create /path/to/mirror --casks firefox visual-studio-code
```

### Transfer to Air-Gapped System

```bash
# Create archive
tar -czvf stout-mirror.tar.gz /path/to/mirror

# Transfer via approved method (USB, secure file transfer, etc.)
# On air-gapped system:
tar -xzvf stout-mirror.tar.gz -C /opt/
```

### Configure for Offline Use

**~/.stout/config.toml:**
```toml
[index]
# Point to local mirror
base_url = "file:///opt/stout-mirror"

[security]
# May need to adjust for offline use
allow_unsigned = true  # Or use your own signing key
```

### Serve Mirror on Internal Network

```bash
# Start HTTP server
stout mirror serve /opt/stout-mirror --port 8080 --bind 0.0.0.0

# Or use nginx/Apache for production
```

### Update Mirror

```bash
# On internet-connected system
stout mirror update /path/to/mirror

# Verify integrity
stout mirror verify /path/to/mirror

# Transfer updated files
rsync -av /path/to/mirror/ user@airgapped:/opt/stout-mirror/
```

### Mirror Security Options

Mirrors support two security models:

**Option 1: Preserve Upstream Signatures (Recommended)**

The mirror preserves the original official signature:

```bash
# Create mirror - upstream signature is automatically preserved
stout mirror create /path/to/mirror jq curl git

# The manifest.json will include:
# {
#   "upstream_signature": {
#     "signature": "original_ed25519_sig...",
#     "index_sha256": "original_hash...",
#     "signed_at": 1732723200
#   }
# }
```

Clients verify against the official stout public key.

**Option 2: Enterprise Re-signing**

Sign the mirror with your own key for full control:

```bash
# Generate enterprise keypair (one-time)
cd /path/to/signing-tools
uv run python sign_index.py generate --output ./keys
# Save keys/stout-index.key securely (e.g., HashiCorp Vault)
# Distribute keys/stout-index.pub to clients

# Sign the mirror
uv run python sign_index.py sign \
    --key ./keys/stout-index.key \
    --index-dir /path/to/mirror

# Configure clients
# ~/.stout/config.toml
[security]
additional_trusted_keys = ["YOUR_ENTERPRISE_PUBLIC_KEY"]
```

**Comparison:**

| Aspect | Preserve Upstream | Enterprise Re-sign |
|--------|-------------------|-------------------|
| Setup complexity | None | Requires key management |
| Trust chain | Official → Mirror → Client | Enterprise → Client |
| Key rotation | Handled by stout team | Self-managed |
| Custom packages | Not supported | Fully supported |
| Audit trail | Traceable to official | Internal only |

## Multi-Prefix Environments

Isolate dependencies for different projects or teams.

### Project-Specific Prefixes

```bash
# Create isolated environment for project
stout prefix create ~/projects/api-service/.stout

# Install project dependencies
stout --prefix=~/projects/api-service/.stout bundle install

# Activate in shell
export PATH="$HOME/projects/api-service/.stout/bin:$PATH"
export STOUT_PREFIX="$HOME/projects/api-service/.stout"
```

### Team-Shared Prefixes

```bash
# Create shared prefix
sudo stout prefix create /opt/team-data-science

# Set permissions
sudo chown -R :data-science /opt/team-data-science
sudo chmod -R g+w /opt/team-data-science

# Team members use
stout --prefix=/opt/team-data-science install pandas numpy scipy
```

### Container Integration

**Dockerfile:**
```dockerfile
FROM ubuntu:22.04

# Install stout
RUN curl -fsSL https://raw.githubusercontent.com/neul-labs/stout/main/install.sh | bash

# Create app-specific prefix
RUN stout prefix create /app/.stout

# Install dependencies
COPY Brewfile /app/
RUN stout --prefix=/app/.stout bundle install

# Add to PATH
ENV PATH="/app/.stout/bin:$PATH"
ENV STOUT_PREFIX="/app/.stout"

COPY . /app
WORKDIR /app
CMD ["./start.sh"]
```

## Audit Logging

Track package operations for compliance and debugging.

### Enable Audit Logging

**~/.stout/config.toml:**
```toml
[audit]
enabled = true
log_file = "/var/log/stout/audit.log"
log_format = "json"  # or "text"
include_user = true
include_timestamp = true
```

### Log Format

**JSON format:**
```json
{
  "timestamp": "2024-11-27T12:00:00Z",
  "user": "developer",
  "action": "install",
  "packages": ["jq@1.7.1"],
  "success": true,
  "duration_ms": 1234,
  "source": "bottle"
}
```

### Centralized Logging

Send logs to your SIEM or log aggregator:

```bash
# Syslog
logger -t stout "$(cat /var/log/stout/audit.log)"

# Fluent Bit / Fluentd
# Configure to tail /var/log/stout/audit.log

# Datadog
# Use the Datadog agent with log collection
```

## Compliance

### SOC 2

stout supports SOC 2 compliance through:

1. **Access controls**: Package installation requires appropriate permissions
2. **Audit trails**: All operations logged with timestamps and users
3. **Change management**: Version control via lock files
4. **Vulnerability management**: Built-in `stout audit` command

### HIPAA

For HIPAA-regulated environments:

1. **Air-gapped operation**: No external network access required
2. **Encrypted storage**: Compatible with encrypted filesystems
3. **Access logging**: Track who installed what and when

### FedRAMP

Federal deployments can use:

1. **Private hosting**: No dependency on external services
2. **Custom signing**: Own cryptographic keys
3. **FIPS compliance**: Uses standard cryptographic algorithms

## Performance at Scale

### Caching Strategies

**Shared Cache for Build Agents:**
```bash
# NFS mount
mount -t nfs cache-server:/stout-cache /opt/stout-cache

# Configure stout
export STOUT_CACHE_DIR=/opt/stout-cache
```

**Redis Cache for Metadata:**
```toml
[cache]
backend = "redis"
redis_url = "redis://cache-server:6379/0"
```

### Parallel Operations

```bash
# Increase parallel downloads
stout config set install.parallel_downloads 8

# Parallel builds (source installation)
stout install -s --jobs=16 large-package
```

### Monitoring

Export metrics for monitoring:

```bash
# Prometheus metrics endpoint
stout metrics serve --port 9090

# Metrics available:
# - stout_packages_installed
# - stout_cache_hit_ratio
# - stout_download_duration_seconds
# - stout_install_duration_seconds
```

## Quick Reference

### Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `STOUT_PREFIX` | Installation prefix | `/opt/homebrew` |
| `STOUT_CACHE_DIR` | Cache directory | `~/.stout/cache` |
| `STOUT_CONFIG` | Config file path | `~/.stout/config.toml` |
| `STOUT_INDEX_URL` | Index URL override | (from config) |
| `STOUT_GITHUB_TOKEN` | GitHub auth token | (none) |
| `STOUT_SIGNING_KEY` | Signing key (CI) | (none) |
| `STOUT_LOG_LEVEL` | Log verbosity | `info` |
| `STOUT_NO_COLOR` | Disable colors | `false` |

### CLI Flags for Enterprise

```bash
# Use specific prefix
stout --prefix=/custom/path install pkg

# Verbose output for debugging
stout -v install pkg
stout -vv install pkg  # More verbose

# Skip signature verification (development only)
stout update --insecure

# Dry run (show what would happen)
stout install --dry-run pkg

# Force operations
stout install --force pkg
```

---

For additional enterprise support, contact the maintainers or open a discussion on GitHub.