CodeSampleX

Пример

ci-info 4.4.0

Проверенный пример — npm ci-info 4.4.0. Контракт выполнен на node 22 · linux alpine/x64 · docker и пройден: ci-info exports boolean isCI and nullable isPR…

sha256:ca8d11430c4b52d4e17d46a3853c183880ee443653546bdfa2c06afe12a1f673

Эта сеть предлагает одно: образец, который собирается. Она запустила его в песочнице и сохранила подписанную квитанцию. Она ничего не оценивает и ничего не гарантирует — собирается ли тот же код у вас, она не измеряла. Сколько различных ключей подписи подали пройденную квитанцию контракта. Один — только автор; больше одного — значит, кто-то ещё тоже собрал. Ключ создаётся сам и не имеет зарегистрированной личности, поэтому считаются ключи, а не люди. MIT-0

Свидетельства выполнения

Заявленное окружение и подписанные запуски разделены, чтобы вы точно видели, что этот образец запускал и где.

Основа свидетельства
Подписанный контракт пройден
Квитанции проверки
1
Ключи подписи, собравшие его
1
Заявленная среда linux 24 · ubuntu · glibc 2.39 x64 npm

Среды запусков проверки

Окружение Контракт Этапы Запуск
node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5…
2026-08-23

Кейс

HOW
Цель
verify pkg:npm/ci-info@4.4.0
Пакеты
Создан
2026-08-23T13:45:43Z

Контракт

  1. ci-info exports boolean isCI and nullable isPR, name, and id properties
  2. ci-info exports vendor boolean flags including GITHUB_ACTIONS, GITLAB, CIRCLE, and VERCEL
  3. ci-info detects GitHub Actions environment and pull request status
  4. ci-info detects GitLab CI environment and merge request status
  5. ci-info detects CircleCI environment when CIRCLECI is set
  6. ci-info respects CI=false environment override to disable all CI detection flags

Файлы

  • PROMPT.md
  • csx.json
  • index.js
  • package-lock.json
  • package.json
  • spec.json
  • test/contract.cjs

Скачать артефакт с исходным кодом (tar.gz)

Исходный код

PROMPT.md
Clean-room public code sample — generation instructions

Write a brand-new, minimal, self-contained code sample in this clean-room directory.
Do not copy, paraphrase, or reference any existing project source. Work only from this spec.

A csx.json manifest scaffold already exists. Do not recreate it from memory. Preserve its case.goal, packages and symbols; fill its empty case.contract with exact assertions and correct its environment, commands and verifierAdapter for the files you generate.

Goal: verify pkg:npm/ci-info@4.4.0
Kind: HOW

Use EXACTLY these public packages and versions:
  - pkg:npm/ci-info@4.4.0

Rules:
  - One focused purpose; the smallest project that proves the goal.
  - Include a contract test (test/contract.*) that runs OFFLINE and exits 0 exactly when the goal behavior works.
  - Pin every dependency with a lockfile so resolution is reproducible.
  - No secrets, credentials, or tokens. No real URLs (only example.com or localhost). No absolute paths.
  - No personal names, emails, company names, or project identifiers of any kind.
  - No binaries and no generated output (node_modules, dist, target, venv, .git, .env).
  - Keep it under 200 files and 256KB packed.
csx.json
{"case":{"caseId":"case:sha256:db2c02bbd059b954581581422dde3d72b8d15781fe40c7c4c6f8ec97134d555f","contract":["ci-info exports boolean isCI and nullable isPR, name, and id properties","ci-info exports vendor boolean flags including GITHUB_ACTIONS, GITLAB, CIRCLE, and VERCEL","ci-info detects GitHub Actions environment and pull request status","ci-info detects GitLab CI environment and merge request status","ci-info detects CircleCI environment when CIRCLECI is set","ci-info respects CI=false environment override to disable all CI detection flags"],"goal":"verify pkg:npm/ci-info@4.4.0","kind":"HOW","packages":["pkg:npm/ci-info@4.4.0"],"schemaVersion":1},"contractCommand":["node","test/contract.cjs"],"environment":{"arch":"x64","distro":"ubuntu","ecosystem":"npm","libc":"glibc","libcVersion":"2.39","os":"linux","osVersionBucket":"24","packageManager":"npm","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/ci-info@4.4.0"],"schemaVersion":1,"subject":"pkg:npm/ci-info@4.4.0","verifierAdapter":"node-typescript@1"}
index.js
'use strict';

const ci = require('ci-info');

/**
 * Returns a summary of current CI environment info.
 * @returns {{ isCI: boolean, isPR: boolean | null, name: string | null, id: string | null }}
 */
function getCISummary() {
  return {
    isCI: ci.isCI,
    isPR: ci.isPR,
    name: ci.name,
    id: ci.id
  };
}

/**
 * Checks if a specific vendor flag is active on the current ci-info export.
 * @param {string} vendorKey
 * @returns {boolean}
 */
function isVendorActive(vendorKey) {
  return Boolean(ci[vendorKey]);
}

/**
 * Returns the list of vendor constants supported by ci-info.
 * @returns {string[]}
 */
function getSupportedVendors() {
  if (Array.isArray(ci._vendors)) {
    return ci._vendors.slice();
  }
  return [];
}

/**
 * Evaluates ci-info behavior under a custom set of environment variables in isolation.
 * @param {Record<string, string>} customEnv
 * @returns {Record<string, any>}
 */
function evaluateWithEnv(customEnv) {
  const originalEnv = { ...process.env };
  try {
    for (const key of Object.keys(process.env)) {
      if (
        key.startsWith('CI') ||
        key.startsWith('GITHUB') ||
        key.startsWith('GITLAB') ||
        key.startsWith('CIRCLE') ||
        key.startsWith('TRAVIS') ||
        key.startsWith('VERCEL') ||
        key.startsWith('NETLIFY') ||
        key === 'CONTINUOUS_INTEGRATION' ||
        key === 'BUILD_ID' ||
        key === 'BUILD_NUMBER' ||
        key === 'RUN_ID'
      ) {
        delete process.env[key];
      }
    }
    Object.assign(process.env, customEnv);

    const ciPath = require.resolve('ci-info');
    delete require.cache[ciPath];

    const freshCi = require('ci-info');
    return freshCi;
  } finally {
    for (const key of Object.keys(process.env)) {
      if (!(key in originalEnv)) {
        delete process.env[key];
      }
    }
    Object.assign(process.env, originalEnv);
    const ciPath = require.resolve('ci-info');
    delete require.cache[ciPath];
  }
}

module.exports = {
  ci,
  getCISummary,
  isVendorActive,
  getSupportedVendors,
  evaluateWithEnv
};
package-lock.json
{
  "name": "sample-ci-info",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "sample-ci-info",
      "version": "1.0.0",
      "license": "MIT-0",
      "dependencies": {
        "ci-info": "4.4.0"
      }
    },
    "node_modules/ci-info": {
      "version": "4.4.0",
      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz",
      "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/sibiraj-s"
        }
      ],
      "license": "MIT",
      "engines": {
        "node": ">=8"
      }
    }
  }
}
package.json
{
  "name": "sample-ci-info",
  "version": "1.0.0",
  "private": true,
  "description": "verify pkg:npm/ci-info@4.4.0",
  "main": "index.js",
  "scripts": {
    "test": "node test/contract.cjs"
  },
  "dependencies": {
    "ci-info": "4.4.0"
  },
  "license": "MIT-0"
}
spec.json
{
  "schemaVersion": 1,
  "goal": "verify pkg:npm/ci-info@4.4.0",
  "kind": "HOW",
  "packages": [
    "pkg:npm/ci-info@4.4.0"
  ]
}
test/contract.cjs
'use strict';

const assert = require('assert');
const {
  ci,
  getCISummary,
  isVendorActive,
  getSupportedVendors,
  evaluateWithEnv
} = require('../index.js');

async function testBaselineContract() {
  assert.strictEqual(typeof ci.isCI, 'boolean', 'ci.isCI should be a boolean');
  assert.ok(ci.isPR === null || typeof ci.isPR === 'boolean', 'ci.isPR should be boolean or null');
  assert.ok(ci.name === null || typeof ci.name === 'string', 'ci.name should be string or null');
  assert.ok(ci.id === null || typeof ci.id === 'string', 'ci.id should be string or null');

  const summary = getCISummary();
  assert.strictEqual(summary.isCI, ci.isCI);
  assert.strictEqual(summary.isPR, ci.isPR);
  assert.strictEqual(summary.name, ci.name);
  assert.strictEqual(summary.id, ci.id);

  const vendors = getSupportedVendors();
  assert.ok(Array.isArray(vendors), 'vendors should be an array');
  assert.ok(vendors.includes('GITHUB_ACTIONS'), 'vendors should include GITHUB_ACTIONS');
  assert.ok(vendors.includes('GITLAB'), 'vendors should include GITLAB');
  assert.ok(vendors.includes('CIRCLE'), 'vendors should include CIRCLE');
  assert.ok(vendors.includes('VERCEL'), 'vendors should include VERCEL');
}

async function testGitHubActionsDetection() {
  const ghEnv = evaluateWithEnv({
    GITHUB_ACTIONS: 'true'
  });
  assert.strictEqual(ghEnv.isCI, true, 'isCI must be true under GitHub Actions');
  assert.strictEqual(ghEnv.name, 'GitHub Actions', 'name must be GitHub Actions');
  assert.strictEqual(ghEnv.id, 'GITHUB_ACTIONS', 'id must be GITHUB_ACTIONS');
  assert.strictEqual(ghEnv.GITHUB_ACTIONS, true, 'GITHUB_ACTIONS flag must be true');
  assert.strictEqual(ghEnv.GITLAB, false, 'GITLAB flag must be false under GitHub Actions');
  assert.strictEqual(ghEnv.isPR, false, 'isPR must be false when not in PR event');

  const ghPrEnv = evaluateWithEnv({
    GITHUB_ACTIONS: 'true',
    GITHUB_EVENT_NAME: 'pull_request'
  });
  assert.strictEqual(ghPrEnv.isCI, true, 'isCI must be true in PR build');
  assert.strictEqual(ghPrEnv.isPR, true, 'isPR must be true when GITHUB_EVENT_NAME is pull_request');
}

async function testGitLabDetection() {
  const gitlabEnv = evaluateWithEnv({
    GITLAB_CI: 'true'
  });
  assert.strictEqual(gitlabEnv.isCI, true, 'isCI must be true under GitLab CI');
  assert.strictEqual(gitlabEnv.name, 'GitLab CI', 'name must be GitLab CI');
  assert.strictEqual(gitlabEnv.id, 'GITLAB', 'id must be GITLAB');
  assert.strictEqual(gitlabEnv.GITLAB, true, 'GITLAB flag must be true');
  assert.strictEqual(gitlabEnv.GITHUB_ACTIONS, false, 'GITHUB_ACTIONS flag must be false');
  assert.strictEqual(gitlabEnv.isPR, false, 'isPR must be false when CI_MERGE_REQUEST_ID is not set');

  const gitlabMrEnv = evaluateWithEnv({
    GITLAB_CI: 'true',
    CI_MERGE_REQUEST_ID: '42'
  });
  assert.strictEqual(gitlabMrEnv.isCI, true, 'isCI must be true in GitLab MR');
  assert.strictEqual(gitlabMrEnv.isPR, true, 'isPR must be true when CI_MERGE_REQUEST_ID is present');
}

async function testCircleAndVercelDetection() {
  const circleEnv = evaluateWithEnv({
    CIRCLECI: 'true'
  });
  assert.strictEqual(circleEnv.isCI, true, 'isCI must be true under CircleCI');
  assert.strictEqual(circleEnv.name, 'CircleCI', 'name must be CircleCI');
  assert.strictEqual(circleEnv.id, 'CIRCLE', 'id must be CIRCLE');
  assert.strictEqual(circleEnv.CIRCLE, true, 'CIRCLE flag must be true');

  const vercelEnv = evaluateWithEnv({
    VERCEL: '1'
  });
  assert.strictEqual(vercelEnv.isCI, true, 'isCI must be true under Vercel');
  assert.strictEqual(vercelEnv.name, 'Vercel', 'name must be Vercel');
  assert.strictEqual(vercelEnv.id, 'VERCEL', 'id must be VERCEL');
  assert.strictEqual(vercelEnv.VERCEL, true, 'VERCEL flag must be true');
}

async function testCIOverride() {
  const overrideEnv = evaluateWithEnv({
    GITHUB_ACTIONS: 'true',
    CI: 'false'
  });
  assert.strictEqual(overrideEnv.isCI, false, 'isCI must be false when CI=false override is set');
  assert.strictEqual(overrideEnv.name, null, 'name must be null when CI=false override is set');
  assert.strictEqual(overrideEnv.id, null, 'id must be null when CI=false override is set');
  assert.strictEqual(overrideEnv.isPR, null, 'isPR must be null when CI=false override is set');
  assert.strictEqual(Boolean(overrideEnv.GITHUB_ACTIONS), false, 'GITHUB_ACTIONS flag must be inactive when CI=false override is set');
}

async function main() {
  await testBaselineContract();
  await testGitHubActionsDetection();
  await testGitLabDetection();
  await testCircleAndVercelDetection();
  await testCIOverride();
  console.log('Contract tests passed successfully.');
}

main().catch((err) => {
  console.error('Contract test failed:', err);
  process.exit(1);
});

Исходный сидер

аноним