{"record":{"id":"4a54c5c364c7f566","repo":"github/spec-kit","slug":"script-entry-must-be-a-relative-path-without","errorCode":null,"errorMessage":"Script entry must be a relative path without '..': {script_entry}","messagePattern":"Script entry must be a relative path without '\\.\\.': (.+?)","errorType":"validation","errorClass":"IntegrationDescriptorError","httpStatus":null,"severity":"error","filePath":"src/specify_cli/integrations/catalog.py","lineNumber":813,"sourceCode":"            if not isinstance(cmd_name, str) or not cmd_name.strip():\n                raise IntegrationDescriptorError(\n                    \"Command entry 'name' must be a non-empty string\"\n                )\n            if not isinstance(cmd_file, str) or not cmd_file.strip():\n                raise IntegrationDescriptorError(\n                    \"Command entry 'file' must be a non-empty string\"\n                )\n            if os.path.isabs(cmd_file) or \"..\" in Path(cmd_file).parts or Path(cmd_file).drive or Path(cmd_file).anchor:\n                raise IntegrationDescriptorError(\n                    f\"Command entry 'file' must be a relative path without '..': {cmd_file}\"\n                )\n        for script_entry in scripts:\n            if not isinstance(script_entry, str) or not script_entry.strip():\n                raise IntegrationDescriptorError(\n                    \"Script entry must be a non-empty string\"\n                )\n            if os.path.isabs(script_entry) or \"..\" in Path(script_entry).parts or Path(script_entry).drive or Path(script_entry).anchor:\n                raise IntegrationDescriptorError(\n                    f\"Script entry must be a relative path without '..': {script_entry}\"\n                )\n\n    # -- Property accessors -----------------------------------------------\n\n    @property\n    def id(self) -> str:\n        return self.data[\"integration\"][\"id\"]\n\n    @property\n    def name(self) -> str:\n        return self.data[\"integration\"][\"name\"]\n\n    @property\n    def version(self) -> str:\n        return self.data[\"integration\"][\"version\"]\n\n    @property","sourceCodeStart":795,"sourceCodeEnd":831,"githubUrl":"https://github.com/github/spec-kit/blob/bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c/src/specify_cli/integrations/catalog.py#L795-L831","documentation":"Raised by IntegrationDescriptor._validate() (src/specify_cli/integrations/catalog.py:813) when a provides.scripts entry is an absolute path, contains '..', or carries a drive/anchor component. Scripts are resolved inside the integration package, so only simple relative paths are accepted; the offending script_entry appears in the message.","triggerScenarios":"'provides: scripts: [/usr/local/bin/setup.sh]' or 'scripts: [../../lib/setup.sh]'; the combined isabs/'..'/drive/anchor check raises with the concrete path.","commonSituations":"Pointing at a system-wide script installed elsewhere on the machine; referencing a shared scripts directory outside the integration; Windows drive-letter paths copied into the descriptor.","solutions":["Vendor the script into the integration package and reference it with a plain relative path.","Strip leading slashes, drive letters, and '..' segments from the entry.","Re-validate the descriptor."],"exampleFix":"# before\nprovides:\n  scripts:\n    - /opt/shared/setup.sh\n\n# after\nprovides:\n  scripts:\n    - scripts/bash/setup.sh","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef unsafe_scripts(scripts):\n    return [s for s in scripts\n            if Path(s).is_absolute() or \"..\" in Path(s).parts\n            or Path(s).drive or Path(s).anchor]","typeGuard":"def is_safe_script_path(s: str) -> bool:\n    p = Path(s)\n    return not p.is_absolute() and \"..\" not in p.parts and not p.drive and not p.anchor","tryCatchPattern":null,"preventionTips":["Vendor shared scripts into the integration package instead of absolute references.","Run a path-safety lint on descriptor entries in CI.","Avoid '..' and drive-letter paths anywhere in provides."],"tags":["path-traversal","security","yaml","validation","spec-kit"],"backgroundTag":null,"analyzedSha":"bf88c9f9a82fa370c7a7257aa2b3cf10b457b65c","analyzedAt":"2026-08-14T19:43:37.150Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}