fix(desktop): keep pip downloads and cache files out of Artifacts
021950ac81 stopped indexing arbitrary dotted paths, but terminal output
is still scanned for bare URLs and looksLikeArtifact accepts any
http(s) value. Installing from a PyPI mirror logs every download with
its full URL (the .whl, its .whl.metadata, sdists under /packages/),
so each one landed in the Artifacts menu; sdists pip reports under its
cache dir (AppData\Local\pip\Cache, ~/.cache/pip, Library/Caches/pip)
were indexed too. Heuristic candidates that are wheels, package-index
dist downloads, or files under pip's cache are now dropped; explicit
MEDIA deliveries are unaffected.
Co-authored-by: yungchentang <46495124+yungchentang@users.noreply.github.com>
This commit is contained in:
@@ -56,7 +56,40 @@ const SCREENSHOT_PATH_RE = /Screenshot path:\s*([^\r\n<>]+)/gi
|
|||||||
// scraped heuristically out of prose or a tool payload.
|
// scraped heuristically out of prose or a tool payload.
|
||||||
type PushValue = (value: string, explicit?: boolean) => void
|
type PushValue = (value: string, explicit?: boolean) => void
|
||||||
|
|
||||||
|
// pip's own traffic, not session output (#52972): terminal output logs every
|
||||||
|
// download (`Downloading https://<index>/packages/…/pkg-1.0-py3-none-any.whl`,
|
||||||
|
// plus its `.whl.metadata`) and cached files live under pip's cache dir.
|
||||||
|
const PIP_CACHE_DIR_RE = /\/(?:\.cache\/pip|library\/caches\/pip|appdata\/local\/pip\/cache)\//
|
||||||
|
const WHEEL_RE = /\.whl(?:\.metadata)?$/
|
||||||
|
const PACKAGE_INDEX_DIST_RE = /\/packages\/.+\.(?:tar\.gz|tar\.bz2|zip|egg)(?:\.metadata)?$/
|
||||||
|
|
||||||
|
function artifactPathForFiltering(value: string): string {
|
||||||
|
if (/^(?:https?|file):\/\//i.test(value)) {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(new URL(value).pathname).toLowerCase()
|
||||||
|
} catch {
|
||||||
|
// Malformed URL: fall through to plain string normalization.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.replace(/\\/g, '/').toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
function isPythonPackageDownload(value: string): boolean {
|
||||||
|
const path = artifactPathForFiltering(value)
|
||||||
|
|
||||||
|
return (
|
||||||
|
PIP_CACHE_DIR_RE.test(path) ||
|
||||||
|
WHEEL_RE.test(path) ||
|
||||||
|
(/^https?:\/\//i.test(value) && PACKAGE_INDEX_DIST_RE.test(path))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function looksLikeArtifact(value: string, explicit = false): boolean {
|
function looksLikeArtifact(value: string, explicit = false): boolean {
|
||||||
|
if (!explicit && isPythonPackageDownload(value)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if (/^(?:https?:\/\/|data:image\/)/.test(value)) {
|
if (/^(?:https?:\/\/|data:image\/)/.test(value)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -251,6 +251,36 @@ ${payload}
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #52972: pip logs every download with its full URL when the index is not
|
||||||
|
// files.pythonhosted.org (a mirror), and on Windows reports sdists under
|
||||||
|
// its cache dir. None of that is something the session produced.
|
||||||
|
it('does not index pip downloads or cache files from terminal output', () => {
|
||||||
|
const mirror = 'https://mirror.example.com/pypi/packages/7a/1b/0f3c'
|
||||||
|
const report = '/home/example/project/report.pdf'
|
||||||
|
const release = 'https://github.com/example/tool/archive/refs/tags/v1.0.tar.gz'
|
||||||
|
|
||||||
|
const artifacts = collectArtifactsForSession(makeSession({ id: 'pip-session' }), [
|
||||||
|
{
|
||||||
|
content: JSON.stringify({
|
||||||
|
output: [
|
||||||
|
'Collecting anthropic',
|
||||||
|
` Downloading ${mirror}/anthropic-0.46.0-py3-none-any.whl.metadata (23 kB)`,
|
||||||
|
` Downloading ${mirror}/anthropic-0.46.0-py3-none-any.whl (223 kB)`,
|
||||||
|
` Downloading ${mirror}/jiter-0.8.2.tar.gz (163 kB)`,
|
||||||
|
' Saved C:\\Users\\Alice\\AppData\\Local\\pip\\Cache\\http-v2\\a\\b\\docstring_parser-0.16.tar.gz',
|
||||||
|
`Wrote ${report}; upstream release: ${release}`
|
||||||
|
].join('\n'),
|
||||||
|
exit_code: 0
|
||||||
|
}),
|
||||||
|
role: 'tool',
|
||||||
|
timestamp: 1_781_774_001,
|
||||||
|
tool_name: 'terminal'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(artifacts.map(artifact => artifact.value).sort()).toEqual([report, release].sort())
|
||||||
|
})
|
||||||
|
|
||||||
it('does not treat an arbitrary dotted absolute path as an artifact', () => {
|
it('does not treat an arbitrary dotted absolute path as an artifact', () => {
|
||||||
const artifacts = collectArtifactsForSession(makeSession(), [
|
const artifacts = collectArtifactsForSession(makeSession(), [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user