承接 innobrain/soak-time 相关项目开发

从需求分析到上线部署,全程专人跟进,保证项目质量与交付效率

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

innobrain/soak-time

最新稳定版本:v1.7.0

Composer 安装命令:

composer require innobrain/soak-time

包简介

Protects against supply chain attacks by filtering recently published packages.

README 文档

README

Latest Version on Packagist Total Downloads

Innobrain Soak Time 🛡️

A Composer plugin that enforces a soak time — a minimum age — on every package version before install. New releases stay out of the solver pool until they age past the threshold, blocking zero-day malicious releases (typosquats, account takeovers, malicious co-maintainer pushes).

A date filter alone is defeatable: an attacker can force-push an old tag at a malicious commit with a backdated GIT_COMMITTER_DATE, and Packagist serves that timestamp. Packagist.org locks the source and dist reference of stable versions and refuses moved tags (composer/packagist#1742, docs) — but only for stable versions on packagist.org. The plugin pins each version's git SHA, source URL, dist URL, and dist sha256 in composer-integrity.lock, extending that protection to dev versions, the local download cache, and non-packagist sources, and hard-fails on any later drift. See SECURITY_MODEL.md.

🧭 How it works

Four checks run on every install/update:

Check Hook Catches
Timestamp filter (PackageFilter) PRE_POOL_CREATE Fresh malicious releases — drops versions younger than the soak time from the solver pool.
Reference drift (ReferenceDriftCheck) PRE_POOL_CREATE Altered historical releases — a backdated GIT_COMMITTER_DATE still changes the content-addressed SHA, which can't be forged.
Hash pinning (HashVerifier) POST_FILE_DOWNLOAD Cache poisoning at ~/.composer/cache/files/ — re-hashes the downloaded archive (Composer's native sha1 is empty for GitHub zips).
Source pinning (PackageIntegrityRecorder) POST_PACKAGE_INSTALL / POST_PACKAGE_UPDATE --prefer-source installs; fails closed if a dist install never exposes its archive.

Pins are written to composer-integrity.lock when a version is first seen (trust-on-first-use) and verified on every later run.

📦 Installation

composer require --dev innobrain/soak-time   # project
composer global require innobrain/soak-time  # all local projects

Upgrading from ≤ v1.3.0? composer update fails because the old SoakTimeConfig is still in PHP memory. Reinstall instead: composer global remove innobrain/soak-time && composer global require innobrain/soak-time (or the --dev equivalents).

⚙️ Configuration

Default soak time is 168h (7 days). Configure via extra in composer.json:

{
    "extra": {
        "soak-time-hours": 168,
        "soak-time-whitelist": ["roave/security-advisories", "your-company/*"],
        "soak-time-dev-branches": ["your-company/my-lib"]
    }
}
  • Per-run override: SOAK_TIME_HOURS=336 composer update (takes precedence; ignored with a warning if not a non-negative integer).
  • Whitelist bypasses the soak filter for trusted packages that update constantly. * is allowed in the name half only — the vendor must be a literal (your-company/*, your-company/lib-*). Vendor-side wildcards (*/x, */*, *) are rejected. SOAK_TIME_SKIP accepts the same patterns.
  • Versions with no release date are filtered unless whitelisted. Whitelist path/internal repos only if you trust their metadata.

Windows PowerShell sets env vars as $env:SOAK_TIME_HOURS=336; composer update.

Dev branches (soak-time-dev-branches)

Dev versions like dev-main or 1.x-dev are mutable — their sourceReference (git SHA) legitimately changes every time the branch advances. By default the plugin treats every version as immutable and hard-fails if a pinned reference drifts. That would make composer update permanently broken for any dev-branch dependency once the branch advances.

Declare the packages whose dev versions are intentionally mutable:

{
    "extra": {
        "soak-time-dev-branches": ["your-company/my-lib", "your-company/*"]
    }
}

Or pass the list as a comma-separated env var for a one-run override:

SOAK_TIME_DEV_BRANCHES=your-company/my-lib composer update

Patterns follow the same rules as the whitelist — vendor must be a literal, * is allowed only in the name half.

Security trade-off: for a declared dev package, the source reference is allowed to advance when isDev() is true. However, if the reference is unchanged but the downloaded archive's sha256 differs, the plugin still hard-fails — that is cache poisoning of a fixed SHA, not legitimate branch movement. Stable versions are never treated as mutable regardless of this list.

Undeclared dev versions whose reference changed are blocked with an error that names soak-time-dev-branches so you know how to unblock them after investigation.

🔐 Integrity lock file

composer-integrity.lock records each version's sha256 (when Composer exposes the archive), sourceReference, sourceUrl, distUrl, and firstSeenAt. Commit it alongside composer.lock — later installs verify against it and hard-fail on drift.

Packages from path repositories are exempt from integrity pinning entirely: they are local code in the same trust domain as the root project, have no archive hash or source reference to pin, and would otherwise fail every install.

Some paths (including plugin self-update) install from dist without exposing the archive; the plugin then fails closed — fix with composer global reinstall innobrain/soak-time --prefer-source. Opt out (not recommended) with soak-time-integrity: false, or relocate via soak-time-integrity-lock:

{
    "extra": {
        "soak-time-integrity": true,
        "soak-time-integrity-lock": "composer-integrity.lock"
    }
}

🚨 Emergency skip

Install a fresh security patch by skipping the freshness filter for one package (integrity checks still run):

SOAK_TIME_SKIP=vendor/package composer update vendor/package

SOAK_TIME_SKIP=1 skips freshness for the whole run.

🔍 Troubleshooting

Run composer update -v to see dropped versions. If the soak time hides every version of a required package, resolution fails — the plugin names the package and its newest version's age up front. Fix by lowering SOAK_TIME_HOURS, whitelisting it, or a one-run SOAK_TIME_SKIP.

🙏 Credits & License

Fork of cotonet/soak-time by Cotonet - Resiliência Digital. MIT License — see LICENSE. Copyright Cotonet - Resiliência Digital (original) and Innobrain GmbH (fork).

统计信息

  • 总下载量: 529
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 2
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-05-21

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固