PHPackages                             jeffersongoncalves/laravel-satis - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Queues &amp; Workers](/categories/queues)
4. /
5. jeffersongoncalves/laravel-satis

ActiveLibrary[Queues &amp; Workers](/categories/queues)

jeffersongoncalves/laravel-satis
================================

A Laravel package for managing private Composer repositories with Satis

v2.0.1(2mo ago)366911MITPHPPHP ^8.2CI passing

Since Feb 16Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/jeffersongoncalves/laravel-satis)[ Packagist](https://packagist.org/packages/jeffersongoncalves/laravel-satis)[ Docs](https://github.com/jeffersongoncalves/laravel-satis)[ GitHub Sponsors](https://github.com/jeffersongoncalves)[ RSS](/packages/jeffersongoncalves-laravel-satis/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (16)Versions (51)Used By (1)

[![Laravel Satis](https://raw.githubusercontent.com/jeffersongoncalves/laravel-satis/main/art/jeffersongoncalves-laravel-satis.png)](https://raw.githubusercontent.com/jeffersongoncalves/laravel-satis/main/art/jeffersongoncalves-laravel-satis.png)

Laravel Satis
=============

[](#laravel-satis)

A Laravel package for managing private Composer repositories powered by [Satis](https://github.com/composer/satis).

Features
--------

[](#features)

- **Credential Management** — Dedicated Credential model for centralized authentication (URL, email, password)
- **Package Management** — Add and manage Composer &amp; GitHub package sources linked to credentials
- **Token-Based Auth** — Secure access with per-token package scoping
- **Automated Builds** — Queue-driven Satis builds with configurable scheduling
- **Credential Grouping** — Separate builds per credential with snapshot merging
- **Inline Auth URLs** — RFC 3986 percent-encoded credentials in repository URLs
- **Rate-Limit Retry** — Exponential backoff on HTTP 429 responses during builds
- **GitHub Webhooks** — Auto-rebuild on push, release and create events with signature verification
- **Download Tracking** — Per-version download statistics
- **Dependency Tracking** — Public/private dependency classification with automatic processing
- **Multi-Tenancy** — Tenant-isolated data with configurable resolver
- **Credential Validation** — Verify package and credential accessibility before building
- **Intelligent Validation** — Timestamp-based comparison to skip unnecessary rebuilds
- **Credential Sanitization** — Remove transport-options and inline credentials from Satis JSON files
- **Dev Packages** — Mark packages as development-only with `is_dev` flag
- **Composer V2 Protocol** — Full support for `packages.json`, `p2/` and include files

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 10+
- Satis (`composer/satis` — included as dependency)

Installation
------------

[](#installation)

```
composer require jeffersongoncalves/laravel-satis
```

Publish and run migrations:

```
php artisan vendor:publish --tag="satis-migrations"
php artisan migrate
```

Publish the config (optional):

```
php artisan vendor:publish --tag="satis-config"
```

Configuration
-------------

[](#configuration)

The config file (`config/satis.php`) covers:

### Multi-Tenancy

[](#multi-tenancy)

```
'tenancy' => [
    'enabled' => false,
    'model' => null,
    'foreign_key' => null,
    'ownership_relationship' => null,
    'resolver' => null, // callable that returns the current tenant ID
],
```

The `resolver` accepts any callable that returns the current tenant ID. Example:

```
// In a service provider or middleware
config(['satis.tenancy.enabled' => true]);
config(['satis.tenancy.model' => \App\Models\Team::class]);
config(['satis.tenancy.foreign_key' => 'team_id']);
config(['satis.tenancy.resolver' => fn () => auth()->user()?->current_team_id]);
```

### Table Prefix

[](#table-prefix)

```
'table_prefix' => 'satis_',
```

Set to `null` to use table names without a prefix.

### Custom Models

[](#custom-models)

Override any model to extend the default behavior:

```
'models' => [
    'credential' => \App\Models\SatisCredential::class,
    'package' => \App\Models\SatisPackage::class,
    'token' => \App\Models\SatisToken::class,
    // ...
],
```

### Storage

[](#storage)

```
'storage_disk' => 'local',
'storage_path' => 'satis',
```

### Queue

[](#queue)

```
'queue' => [
    'connection' => null,  // null = default connection
    'queue_name' => null,  // null = default queue
    'timeout' => 86400,    // 24 hours (in seconds)
],
```

### Scheduling

[](#scheduling)

```
'schedule' => [
    'build' => 'weekly',        // any Laravel Schedule method or null
    'token_build' => 'weekly',
    'validate' => 'hourly',
    'sanitize' => 'daily',
    'dependencies' => 'weekly',
],
```

### Routes

[](#routes)

```
'routes' => [
    'api_prefix' => 'api/satis',
    'composer_prefix' => 'satis',
    'middleware' => ['api'],
],
```

Usage
-----

[](#usage)

### Managing Credentials and Packages Programmatically

[](#managing-credentials-and-packages-programmatically)

```
use JeffersonGoncalves\LaravelSatis\Support\ModelResolver;

// Create a credential
$credentialModel = ModelResolver::credential();
$credential = $credentialModel::create([
    'name' => 'My Private Repo',
    'url' => 'https://repo.example.com',
    'email' => 'user',
    'password' => 'secret',
]);

// Create a package using the credential
$packageModel = ModelResolver::package();
$package = $packageModel::create([
    'name' => 'vendor/package-name',
    'type' => 'composer',
    'credential_id' => $credential->id,
]);

// Create a GitHub credential and package
$githubCredential = $credentialModel::create([
    'name' => 'GitHub',
    'url' => 'https://github.com/vendor/repo.git',
    'email' => 'github-user',
    'password' => 'github-token',
]);

$githubPackage = $packageModel::create([
    'name' => 'vendor/github-package',
    'type' => 'github',
    'credential_id' => $githubCredential->id,
]);

// Create a dev package (reusing same credential)
$devPackage = $packageModel::create([
    'name' => 'vendor/dev-tool',
    'type' => 'composer',
    'credential_id' => $credential->id,
    'is_dev' => true,
]);

// Validate a credential
$result = app(\JeffersonGoncalves\LaravelSatis\Actions\ValidateCredential::class)
    ->execute($credential);
// $result = ['success' => true, 'message' => 'Credential validated successfully.']

// Create a token
$tokenModel = ModelResolver::token();
$token = $tokenModel::create([
    'name' => 'My Token',
    'email' => 'user@example.com',
]);

// Assign packages to token
$token->packages()->attach($package->id);
```

### Running Builds

[](#running-builds)

```
# Build all packages (tenant-based)
php artisan satis:build

# Build for a specific tenant
php artisan satis:build --tenant=1

# Build per token (all tokens with packages)
php artisan satis:token-build

# Build for a specific token
php artisan satis:token-build --token=5

# Validate credentials and trigger rebuilds if needed
php artisan satis:validate

# Process dependencies
php artisan dependency:packages

# Remove credentials from Satis JSON files
php artisan satis:sanitize

# Clean all Satis builds from storage
php artisan satis:clean

# Force clean without confirmation
php artisan satis:clean --force
```

### Composer Client Configuration

[](#composer-client-configuration)

After building, clients can use your private repository:

```
{
    "repositories": [
        {
            "type": "composer",
            "url": "https://your-app.com/satis"
        }
    ]
}
```

Authenticate using the token as a password with any username:

```
composer config http-basic.your-app.com/satis "any-username" "your-token-here"
```

### GitHub Webhooks

[](#github-webhooks)

Each package gets a unique reference for webhook URLs:

```
POST /api/satis/webhooks/github/{package-reference}

```

Set the **Content type** to `application/json` and optionally configure a **Secret** using the package's `webhook_secret`.

**Supported events:** `push`, `release`, `create` — all other events are ignored with HTTP 200.

The webhook handler:

1. Validates the package is a GitHub type (returns 400 otherwise)
2. Filters supported events
3. Verifies HMAC-SHA256 signature when a secret is configured
4. Dispatches `SyncTenantPackages` for the tenant rebuild
5. Dispatches `SyncTokenPackages` for each token associated with the package

API Endpoints
-------------

[](#api-endpoints)

### Composer Protocol (requires token auth)

[](#composer-protocol-requires-token-auth)

MethodEndpointDescription`GET``/satis/packages.json`Root packages file`GET``/satis/include/{include}.json`Include files`GET``/satis/p2/{vendor}/{package}.json`V2 protocol metadata`GET``/satis/archives/{vendor}/{package}/{file}`Package archives### API

[](#api)

MethodEndpointDescription`POST``/api/satis/composer/downloads`Download notifications`POST``/api/satis/webhooks/github/{reference}`GitHub webhookCommands
--------

[](#commands)

CommandDescription`satis:build`Build Satis repository (tenant-based)`satis:token-build`Build Satis repository (token-based)`satis:validate`Validate package credentials and trigger rebuilds if needed`satis:clean`Clean all Satis builds from storage`satis:sanitize`Remove credentials from Satis JSON files`dependency:packages`Process and sync package dependenciesUpgrading from v1.x to v2.0
---------------------------

[](#upgrading-from-v1x-to-v20)

### Breaking Changes

[](#breaking-changes)

1. **Credential model**: Credentials are now stored in a dedicated `credentials` table instead of directly on the `packages` table.
2. **Package model**: The `url`, `username`, and `password` columns have been removed. Packages now reference a `credential_id` foreign key (required).
3. **CreateAuthJson removed**: Authentication is now handled via inline auth URLs (RFC 3986) instead of a separate auth.json file.
4. **Code lengths**: `webhook_secret` changed from 40 to 64 characters, `reference` from 20 to 32 characters.

### Migration Steps

[](#migration-steps)

1. Update your dependency:

```
composer require jeffersongoncalves/laravel-satis:^2.0
```

2. Publish and run the new migrations:

```
php artisan vendor:publish --tag="satis-migrations"
```

3. **Before running migrations**, migrate existing data to the credentials table:

```
use JeffersonGoncalves\LaravelSatis\Models\Credential;

$packages = DB::table('satis_packages')->get();
$credentialMap = [];

foreach ($packages as $package) {
    $key = $package->url . '|' . $package->username;

    if (! isset($credentialMap[$key])) {
        $credential = Credential::create([
            'name' => parse_url($package->url, PHP_URL_HOST) ?? $package->url,
            'url' => $package->url,
            'email' => $package->username,
            'password' => $package->password,
            'is_validated' => $package->is_credentials_validated,
            'validated_at' => $package->credentials_validated_at,
        ]);
        $credentialMap[$key] = $credential->id;
    }

    DB::table('satis_packages')
        ->where('id', $package->id)
        ->update(['credential_id' => $credentialMap[$key]]);
}
```

4. Run migrations:

```
php artisan migrate
```

5. Update code references:
    - `$package->url` → `$package->credential->url`
    - `$package->username` → `$package->credential->email`
    - `$package->password` → `$package->credential->password`
    - `CreateAuthJson` → removed, no longer needed

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

49

—

FairBetter than 95% of packages

Maintenance88

Actively maintained with recent releases

Popularity22

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor1

Top contributor holds 95.5% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

49

Last Release

60d ago

Major Versions

1.17.2 → v2.0.02026-03-13

PHP version history (2 changes)1.0.0PHP ^8.1

1.0.1PHP ^8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/411493?v=4)[Jefferson Gonçalves](/maintainers/jeffersongoncalves)[@jeffersongoncalves](https://github.com/jeffersongoncalves)

---

Top Contributors

[![jeffersongoncalves](https://avatars.githubusercontent.com/u/411493?v=4)](https://github.com/jeffersongoncalves "jeffersongoncalves (105 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (4 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

composercomposer-repositorygithub-webhookslaravellaravel-packagemulti-tenancypackage-managerphpprivate-repositoryqueuesatiswebhookscomposerlaravelrepositorysatisprivate-packages

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/jeffersongoncalves-laravel-satis/health.svg)

```
[![Health](https://phpackages.com/badges/jeffersongoncalves-laravel-satis/health.svg)](https://phpackages.com/packages/jeffersongoncalves-laravel-satis)
```

###  Alternatives

[croustibat/filament-jobs-monitor

Background Jobs monitoring like Horizon for all drivers for FilamentPHP

254255.2k6](/packages/croustibat-filament-jobs-monitor)[harris21/laravel-fuse

Circuit breaker for Laravel queue jobs. Protect your workers from cascading failures.

3786.5k](/packages/harris21-laravel-fuse)[spatie/laravel-interacts-with-payload

Add variables to the payloads of all jobs in a Laravel app

6779.4k](/packages/spatie-laravel-interacts-with-payload)[cybercog/laravel-paket

Composer personal web interface. Manage Laravel dependencies without switching to command line!

1753.3k](/packages/cybercog-laravel-paket)[bytexr/filament-queueable-bulk-actions

This Filament plugin simplifies managing bulk operations asynchronously in a queue. It provides tracking and status updates for tasks, while supporting both action calls and job dispatches. Excellent for bulk data updates and tasks with Filament &amp; Livewire support for real-time notifications.

3668.7k](/packages/bytexr-filament-queueable-bulk-actions)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
