Remove internal-only tooling from the external build (#352)
* Remove internal-only tooling without changing external runtime contracts This trims the lowest-risk internal-only surfaces first: deleted internal modules are replaced by build-time no-op stubs, the bundled stuck skill is removed, and the insights S3 upload path now stays local-only. The privacy verifier is expanded and the remaining bundled internal Slack/Artifactory strings are neutralized without broad repo-wide renames. Constraint: Keep the first PR deletion-heavy and avoid mass rewrites of USER_TYPE, tengu, or claude_code identifiers Rejected: One-shot DMCA cleanup branch | too much semantic risk for a first PR Confidence: medium Scope-risk: moderate Reversibility: clean Directive: Treat full-repo typecheck as a baseline issue on this upstream snapshot; do not claim this commit introduced the existing non-Phase-A errors without isolating them first Tested: bun run build Tested: bun run smoke Tested: bun run verify:privacy Not-tested: Full repo typecheck (currently fails on widespread pre-existing upstream errors outside this change set) * Keep minimal source shims so CI can import Phase A cleanup paths The first PR removed internal-only source files entirely, but CI provider and context tests import those modules directly from source rather than through the build-time no-telemetry stubs. This restores tiny no-op source shims so tests and local source imports resolve while preserving the same external runtime behavior. Constraint: GitHub Actions runs source-level tests in addition to bundled build/privacy checks Rejected: Revert the entire deletion pass | unnecessary once the import contract is satisfied by small shims Confidence: high Scope-risk: narrow Reversibility: clean Directive: For later cleanup phases, treat build-time stubs and source-test imports as separate compatibility surfaces Tested: bun run build Tested: bun run smoke Tested: bun run verify:privacy Tested: bun run test:provider Tested: bun run test:provider-recommendation Not-tested: Full repo typecheck (still noisy on this upstream snapshot) --------- Co-authored-by: anandh8x <test@example.com>
This commit is contained in:
@@ -1390,6 +1390,12 @@ const detectHostIP = memoize(
|
||||
)
|
||||
|
||||
async function installFromArtifactory(command: string): Promise<string> {
|
||||
const artifactoryBaseUrl =
|
||||
process.env.CLAUDE_CODE_INTERNAL_ARTIFACTORY_BASE_URL
|
||||
if (!artifactoryBaseUrl) {
|
||||
throw new Error('Internal artifactory base URL is not configured')
|
||||
}
|
||||
const npmrcAuthPrefix = `//${artifactoryBaseUrl.replace(/^https?:\/\//, '')}/api/npm/npm-all/:_authToken=`
|
||||
// Read auth token from ~/.npmrc
|
||||
const npmrcPath = join(os.homedir(), '.npmrc')
|
||||
let authToken: string | null = null
|
||||
@@ -1402,11 +1408,8 @@ async function installFromArtifactory(command: string): Promise<string> {
|
||||
const lines = npmrcContent.split('\n')
|
||||
for (const line of lines) {
|
||||
// Look for the artifactory auth token line
|
||||
const match = line.match(
|
||||
/\/\/artifactory\.infra\.ant\.dev\/artifactory\/api\/npm\/npm-all\/:_authToken=(.+)/,
|
||||
)
|
||||
if (match && match[1]) {
|
||||
authToken = match[1].trim()
|
||||
if (line.startsWith(npmrcAuthPrefix)) {
|
||||
authToken = line.slice(npmrcAuthPrefix.length).trim()
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -1420,8 +1423,7 @@ async function installFromArtifactory(command: string): Promise<string> {
|
||||
}
|
||||
|
||||
// Fetch the version from artifactory
|
||||
const versionUrl =
|
||||
'https://artifactory.infra.ant.dev/artifactory/armorcode-claude-code-internal/claude-vscode-releases/stable'
|
||||
const versionUrl = `${artifactoryBaseUrl}/armorcode-claude-code-internal/claude-vscode-releases/stable`
|
||||
|
||||
try {
|
||||
const versionResponse = await axios.get(versionUrl, {
|
||||
@@ -1436,7 +1438,7 @@ async function installFromArtifactory(command: string): Promise<string> {
|
||||
}
|
||||
|
||||
// Download the .vsix file from artifactory
|
||||
const vsixUrl = `https://artifactory.infra.ant.dev/artifactory/armorcode-claude-code-internal/claude-vscode-releases/${version}/claude-code.vsix`
|
||||
const vsixUrl = `${artifactoryBaseUrl}/armorcode-claude-code-internal/claude-vscode-releases/${version}/claude-code.vsix`
|
||||
const tempVsixPath = join(
|
||||
os.tmpdir(),
|
||||
`claude-code-${version}-${Date.now()}.vsix`,
|
||||
|
||||
@@ -25,11 +25,14 @@ import { getBinaryName, getPlatform } from './installer.js'
|
||||
const GCS_BUCKET_URL =
|
||||
'https://storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases'
|
||||
export const ARTIFACTORY_REGISTRY_URL =
|
||||
'https://artifactory.infra.ant.dev/artifactory/api/npm/npm-all/'
|
||||
process.env.CLAUDE_CODE_INTERNAL_ARTIFACTORY_REGISTRY_URL ?? ''
|
||||
|
||||
export async function getLatestVersionFromArtifactory(
|
||||
tag: string = 'latest',
|
||||
): Promise<string> {
|
||||
if (!ARTIFACTORY_REGISTRY_URL) {
|
||||
throw new Error('Internal artifactory registry URL is not configured')
|
||||
}
|
||||
const startTime = Date.now()
|
||||
const { stdout, code, stderr } = await execFileNoThrowWithCwd(
|
||||
'npm',
|
||||
@@ -152,6 +155,9 @@ export async function downloadVersionFromArtifactory(
|
||||
version: string,
|
||||
stagingPath: string,
|
||||
) {
|
||||
if (!ARTIFACTORY_REGISTRY_URL) {
|
||||
throw new Error('Internal artifactory registry URL is not configured')
|
||||
}
|
||||
const fs = getFsImplementation()
|
||||
|
||||
// If we get here, we own the lock and can delete a partial download
|
||||
|
||||
@@ -1059,9 +1059,7 @@ export function getAutoModeUnavailableNotification(
|
||||
base = 'auto mode unavailable for this model'
|
||||
break
|
||||
}
|
||||
return process.env.USER_TYPE === 'ant'
|
||||
? `${base} · #claude-code-feedback`
|
||||
: base
|
||||
return base
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,89 +1,11 @@
|
||||
/**
|
||||
* Undercover mode — safety utilities for contributing to public/open-source repos.
|
||||
*
|
||||
* When active, Claude Code adds safety instructions to commit/PR prompts and
|
||||
* strips all attribution to avoid leaking internal model codenames, project
|
||||
* names, or other Anthropic-internal information. The model is not told what
|
||||
* model it is.
|
||||
*
|
||||
* Activation:
|
||||
* - CLAUDE_CODE_UNDERCOVER=1 — force ON (even in internal repos)
|
||||
* - Otherwise AUTO: active UNLESS the repo remote matches the internal
|
||||
* allowlist (INTERNAL_MODEL_REPOS in commitAttribution.ts). Safe default
|
||||
* is ON — Claude may push to public remotes from a CWD that isn't itself
|
||||
* a git checkout (e.g. /tmp crash repro).
|
||||
* - There is NO force-OFF. This guards against model codename leaks — if
|
||||
* we're not confident we're in an internal repo, we stay undercover.
|
||||
*
|
||||
* All code paths are gated on process.env.USER_TYPE === 'ant'. Since USER_TYPE is
|
||||
* a build-time --define, the bundler constant-folds these checks and dead-code-
|
||||
* eliminates the ant-only branches from external builds. In external builds every
|
||||
* function in this file reduces to a trivial return.
|
||||
*/
|
||||
|
||||
import { getRepoClassCached } from './commitAttribution.js'
|
||||
import { getGlobalConfig } from './config.js'
|
||||
import { isEnvTruthy } from './envUtils.js'
|
||||
|
||||
export function isUndercover(): boolean {
|
||||
if (process.env.USER_TYPE === 'ant') {
|
||||
if (isEnvTruthy(process.env.CLAUDE_CODE_UNDERCOVER)) return true
|
||||
// Auto: active unless we've positively confirmed we're in an allowlisted
|
||||
// internal repo. 'external', 'none', and null (check not yet run) all
|
||||
// resolve to ON. The check is primed in setup.ts; only 'internal' → OFF.
|
||||
return getRepoClassCached() !== 'internal'
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export function getUndercoverInstructions(): string {
|
||||
if (process.env.USER_TYPE === 'ant') {
|
||||
return `## UNDERCOVER MODE — CRITICAL
|
||||
|
||||
You are operating UNDERCOVER in a PUBLIC/OPEN-SOURCE repository. Your commit
|
||||
messages, PR titles, and PR bodies MUST NOT contain ANY Anthropic-internal
|
||||
information. Do not blow your cover.
|
||||
|
||||
NEVER include in commit messages or PR descriptions:
|
||||
- Internal model codenames (animal names like Capybara, Tengu, etc.)
|
||||
- Unreleased model version numbers (e.g., opus-4-7, sonnet-4-8)
|
||||
- Internal repo or project names (e.g., claude-cli-internal, anthropics/…)
|
||||
- Internal tooling, Slack channels, or short links (e.g., go/cc, #claude-code-…)
|
||||
- The phrase "Claude Code" or any mention that you are an AI
|
||||
- Any hint of what model or version you are
|
||||
- Co-Authored-By lines or any other attribution
|
||||
|
||||
Write commit messages as a human developer would — describe only what the code
|
||||
change does.
|
||||
|
||||
GOOD:
|
||||
- "Fix race condition in file watcher initialization"
|
||||
- "Add support for custom key bindings"
|
||||
- "Refactor parser for better error messages"
|
||||
|
||||
BAD (never write these):
|
||||
- "Fix bug found while testing with Claude Capybara"
|
||||
- "1-shotted by claude-opus-4-6"
|
||||
- "Generated with Claude Code"
|
||||
- "Co-Authored-By: Claude Opus 4.6 <…>"
|
||||
`
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether to show the one-time explainer dialog for auto-undercover.
|
||||
* True when: undercover is active via auto-detection (not forced via env),
|
||||
* and the user hasn't seen the notice before. Pure — the component marks the
|
||||
* flag on mount.
|
||||
*/
|
||||
export function shouldShowUndercoverAutoNotice(): boolean {
|
||||
if (process.env.USER_TYPE === 'ant') {
|
||||
// If forced via env, user already knows; don't nag.
|
||||
if (isEnvTruthy(process.env.CLAUDE_CODE_UNDERCOVER)) return false
|
||||
if (!isUndercover()) return false
|
||||
if (getGlobalConfig().hasSeenUndercoverAutoNotice) return false
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user