-
Notifications
You must be signed in to change notification settings - Fork 34
feat: add Cursor Agent CLI container image #103
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,10 +4,10 @@ CONTAINER_RUNTIME ?= $(shell command -v podman 2>/dev/null || echo docker) | |||||||||||||||||||||||||||||
| # claudelint image | ||||||||||||||||||||||||||||||
| CLAUDELINT_IMAGE = ghcr.io/stbenjam/claudelint:main | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| # AI helpers image | ||||||||||||||||||||||||||||||
| IMAGE_NAME ?=ai-helpers | ||||||||||||||||||||||||||||||
| # Container images | ||||||||||||||||||||||||||||||
| IMAGE_TAG ?= latest | ||||||||||||||||||||||||||||||
| FULL_IMAGE_NAME = $(IMAGE_NAME):$(IMAGE_TAG) | ||||||||||||||||||||||||||||||
| CLAUDE_IMAGE_NAME ?= ai-helpers | ||||||||||||||||||||||||||||||
| CURSOR_IMAGE_NAME ?= ai-helpers-cursor | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| .PHONY: help | ||||||||||||||||||||||||||||||
| help: ## Show this help message | ||||||||||||||||||||||||||||||
|
|
@@ -58,9 +58,17 @@ update: ## Update Claude settings and website data | |||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| .PHONY: build | ||||||||||||||||||||||||||||||
| build: ## Build Claude container image using Containerfile | ||||||||||||||||||||||||||||||
| @echo "Building Claude container image $(FULL_IMAGE_NAME) with $(CONTAINER_RUNTIME)..." | ||||||||||||||||||||||||||||||
| $(CONTAINER_RUNTIME) build -f images/claude/Containerfile -t $(FULL_IMAGE_NAME) . | ||||||||||||||||||||||||||||||
| build: build-claude build-cursor ## Build all container images | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| .PHONY: build-claude | ||||||||||||||||||||||||||||||
| build-claude: ## Build Claude CLI container image | ||||||||||||||||||||||||||||||
| @echo "Building Claude container image $(CLAUDE_IMAGE_NAME):$(IMAGE_TAG) with $(CONTAINER_RUNTIME)..." | ||||||||||||||||||||||||||||||
| $(CONTAINER_RUNTIME) build -f images/claude/Containerfile -t $(CLAUDE_IMAGE_NAME):$(IMAGE_TAG) . | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| .PHONY: build-cursor | ||||||||||||||||||||||||||||||
| build-cursor: ## Build Cursor CLI container image | ||||||||||||||||||||||||||||||
| @echo "Building Cursor container image $(CURSOR_IMAGE_NAME):$(IMAGE_TAG) with $(CONTAINER_RUNTIME)..." | ||||||||||||||||||||||||||||||
| $(CONTAINER_RUNTIME) build -f images/cursor/Containerfile -t $(CURSOR_IMAGE_NAME):$(IMAGE_TAG) . | ||||||||||||||||||||||||||||||
|
Comment on lines
+65
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π§© Analysis chainπ Script executed: # Find and read the Makefile
fd -name Makefile -type f | head -5Repository: opendatahub-io/ai-helpers Length of output: 299 π Script executed: # Read the Makefile to see the full context
if [ -f Makefile ]; then
wc -l Makefile
cat -n Makefile
fiRepository: opendatahub-io/ai-helpers Length of output: 3695 Quote the image reference in build targets.
Remediation- $(CONTAINER_RUNTIME) build -f images/claude/Containerfile -t $(CLAUDE_IMAGE_NAME):$(IMAGE_TAG) .
+ $(CONTAINER_RUNTIME) build -f images/claude/Containerfile -t "$(CLAUDE_IMAGE_NAME):$(IMAGE_TAG)" .
- $(CONTAINER_RUNTIME) build -f images/cursor/Containerfile -t $(CURSOR_IMAGE_NAME):$(IMAGE_TAG) .
+ $(CONTAINER_RUNTIME) build -f images/cursor/Containerfile -t "$(CURSOR_IMAGE_NAME):$(IMAGE_TAG)" .π Committable suggestion
Suggested change
π€ Prompt for AI Agents |
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| .PHONY: container-build | ||||||||||||||||||||||||||||||
| container-build: build ## Alias for build target | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -195,6 +195,53 @@ claude-container() { | |
| } | ||
| ``` | ||
|
|
||
| ### Running Cursor Agent CLI in a Container | ||
|
|
||
| A container image is also available with the Cursor Agent CLI and all development tools pre-installed: | ||
| `ghcr.io/opendatahub-io/ai-helpers-cursor:latest` | ||
|
|
||
| You can also build it yourself by running: | ||
|
|
||
| ```bash | ||
| podman build -f images/cursor/Containerfile -t ai-helpers-cursor . | ||
| ``` | ||
|
|
||
| Or using make: | ||
|
|
||
| ```bash | ||
| make build-cursor | ||
| ``` | ||
|
|
||
| To use the Cursor Agent CLI, you need to pass your `CURSOR_API_KEY`: | ||
|
|
||
| ```bash | ||
| podman run -it --rm \ | ||
| --pull newer \ | ||
| --userns=keep-id \ | ||
| -e CURSOR_API_KEY=your-api-key \ | ||
| -v $(pwd):$(pwd):z \ | ||
| -w $(pwd) \ | ||
| ghcr.io/opendatahub-io/ai-helpers-cursor:latest | ||
|
Comment on lines
+215
to
+224
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Major: both examples expose Inlining the value in Remediation- -e CURSOR_API_KEY=your-api-key \
+ -e CURSOR_API_KEY \
...
- -e CURSOR_API_KEY="${CURSOR_API_KEY}" \
+ -e CURSOR_API_KEY \Also applies to: 233-241 π€ Prompt for AI Agents |
||
| ``` | ||
|
|
||
| **Environment Variables:** | ||
|
|
||
| - `CURSOR_API_KEY` - Your Cursor API key (required for authentication) | ||
|
|
||
| Add this to your `~/.bashrc` for easy launching of the container: | ||
|
|
||
| ```bash | ||
| cursor-container() { | ||
| podman run -it --rm \ | ||
| --pull newer \ | ||
| --userns=keep-id \ | ||
| -e CURSOR_API_KEY="${CURSOR_API_KEY}" \ | ||
| -v "$(pwd):$(pwd):z" \ | ||
| -w "$(pwd)" \ | ||
| ghcr.io/opendatahub-io/ai-helpers-cursor:latest "$@" | ||
| } | ||
| ``` | ||
|
|
||
| ## Using with OpenCode.ai | ||
|
|
||
| [OpenCode.ai](https://opencode.ai) is an open-source AI coding assistant that supports custom skills and commands. Our helpers can be integrated as OpenCode skills and commands to enhance your development workflow. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| FROM quay.io/fedora/fedora:latest | ||
|
|
||
| # Install Node.js, NPM, Python 3, development tools, and RPM tools | ||
| RUN dnf install -y nodejs \ | ||
| npm \ | ||
| python3 \ | ||
| python3-devel \ | ||
| fedora-packager \ | ||
| fedora-review \ | ||
| mock \ | ||
| rpm-build \ | ||
| rpmdevtools \ | ||
| curl \ | ||
| git \ | ||
| make \ | ||
| shellcheck \ | ||
| which \ | ||
| && dnf clean all | ||
|
|
||
|
|
||
| RUN echo '[google-cloud-cli]' > /etc/yum.repos.d/google-cloud-sdk.repo && \ | ||
| echo 'name=Google Cloud CLI' >> /etc/yum.repos.d/google-cloud-sdk.repo && \ | ||
| echo 'baseurl=https://packages.cloud.google.com/yum/repos/cloud-sdk-el10-$basearch' >> /etc/yum.repos.d/google-cloud-sdk.repo && \ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think they only support x86_64: https://docs.cloud.google.com/sdk/docs/install-sdk#rpm so the |
||
| echo 'enabled=1' >> /etc/yum.repos.d/google-cloud-sdk.repo && \ | ||
| echo 'gpgcheck=1' >> /etc/yum.repos.d/google-cloud-sdk.repo && \ | ||
| echo 'repo_gpgcheck=0' >> /etc/yum.repos.d/google-cloud-sdk.repo && \ | ||
| echo 'gpgkey=https://packages.cloud.google.com/yum/doc/rpm-package-key-v10.gpg' >> /etc/yum.repos.d/google-cloud-sdk.repo && \ | ||
| dnf install -y google-cloud-cli && \ | ||
| dnf clean all | ||
|
|
||
| # Install uv for PEP 723 script dependency management | ||
| RUN curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR="/usr/local/bin/" INSTALLER_NO_MODIFY_PATH=1 sh | ||
|
|
||
|
Comment on lines
+32
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π§© Analysis chainπ Script executed: cat -n images/cursor/Containerfile | sed -n '25,65p'Repository: opendatahub-io/ai-helpers Length of output: 1850 Critical: uv and Cursor installers execute remote scripts without integrity verification (CWE-829). Lines 32 and 58 both pipe unverified remote scripts directly to shell interpreters, allowing arbitrary code execution from upstream sources or CDN compromise during build. Version the installer URLs and verify checksums before execution. Remediation # Install uv for PEP 723 script dependency management
-RUN curl -LsSf https://astral.sh/uv/install.sh | UV_INSTALL_DIR="/usr/local/bin/" INSTALLER_NO_MODIFY_PATH=1 sh
+ARG UV_INSTALL_URL=<versioned-url>
+ARG UV_INSTALL_SHA256=<published-sha256>
+RUN curl -fsSLo /tmp/uv-install.sh "${UV_INSTALL_URL}" \
+ && echo "${UV_INSTALL_SHA256} /tmp/uv-install.sh" | sha256sum -c - \
+ && UV_INSTALL_DIR="/usr/local/bin/" INSTALLER_NO_MODIFY_PATH=1 sh /tmp/uv-install.sh \
+ && rm -f /tmp/uv-install.sh
# Install Cursor CLI
-RUN curl -fsSL https://cursor.com/install | bash
+ARG CURSOR_INSTALL_URL=<versioned-url>
+ARG CURSOR_INSTALL_SHA256=<published-sha256>
+RUN curl -fsSLo /tmp/cursor-install.sh "${CURSOR_INSTALL_URL}" \
+ && echo "${CURSOR_INSTALL_SHA256} /tmp/cursor-install.sh" | sha256sum -c - \
+ && bash /tmp/cursor-install.sh \
+ && rm -f /tmp/cursor-install.shπ€ Prompt for AI Agents |
||
| # Install OpenShift client (oc) | ||
| RUN curl -LsSf https://mirror.openshift.com/pub/openshift-v4/clients/ocp/stable/openshift-client-linux.tar.gz | tar xzf - -C /usr/local/bin/ oc \ | ||
| && chmod +x /usr/local/bin/oc | ||
|
Comment on lines
+35
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π§© Analysis chainπ Script executed: find . -name "Containerfile" -type fRepository: opendatahub-io/ai-helpers Length of output: 128 π Script executed: find . -type f -name "*docker*" -o -name "*compose*" -o -name "*.yml" -o -name "*.yaml" | grep -E "(workflow|action|build)" | head -20Repository: opendatahub-io/ai-helpers Length of output: 264 π Script executed: find . -type f \( -name ".github" -o -name "docker-compose*" \) | head -20Repository: opendatahub-io/ai-helpers Length of output: 51 π Script executed: cd images/cursor && ls -laRepository: opendatahub-io/ai-helpers Length of output: 242 π Script executed: cat -n images/cursor/ContainerfileRepository: opendatahub-io/ai-helpers Length of output: 2949 π Script executed: cat -n .github/workflows/build.ymlRepository: opendatahub-io/ai-helpers Length of output: 2387 π Script executed: web_search
OpenShift mirror openshift-client-linux artifact naming conventions amd64 arm64Repository: opendatahub-io/ai-helpers Length of output: 167 π Web query:
π‘ Result: OpenShift Linux amd64 (x86_64)Red Hat docs also reference this Linux arm64 (aarch64)Commonly published as an explicit arm64 filename: Examples seen in the wild:
βMultiβ layout (also used for arch-separated listings)You may also find arch-separated directories like: Citations:
Major: The build workflow ( Parameterize the archive name using Docker's Remediation+ARG TARGETARCH
-RUN curl -LsSf https://mirror.openshift.com/pub/openshift-v4/clients/ocp/stable/openshift-client-linux.tar.gz | tar xzf - -C /usr/local/bin/ oc \
- && chmod +x /usr/local/bin/oc
+RUN case "${TARGETARCH}" in \
+ amd64) oc_archive="openshift-client-linux.tar.gz" ;; \
+ arm64) oc_archive="openshift-client-linux-arm64.tar.gz" ;; \
+ *) echo "Unsupported TARGETARCH=${TARGETARCH}" >&2; exit 1 ;; \
+ esac \
+ && curl -fsSLo /tmp/oc.tgz "https://mirror.openshift.com/pub/openshift-v4/clients/ocp/stable/${oc_archive}" \
+ && tar xzf /tmp/oc.tgz -C /usr/local/bin/ oc \
+ && chmod +x /usr/local/bin/oc \
+ && rm -f /tmp/oc.tgzπ€ Prompt for AI Agents |
||
|
|
||
| # Install common Python tools | ||
| RUN uv pip install --system --no-cache \ | ||
| pytest \ | ||
| requests \ | ||
| pyyaml \ | ||
| ruff \ | ||
| tox \ | ||
| tox-uv | ||
|
|
||
| # Create cursor user | ||
| RUN useradd -m -u 1000 -s /bin/bash cursor | ||
|
|
||
| # Copy ai-helpers repository to /opt/ai-helpers | ||
| COPY . /opt/ai-helpers | ||
| RUN chown -R cursor:cursor /opt/ai-helpers | ||
|
|
||
| # Switch to cursor user | ||
| USER cursor | ||
|
|
||
| # Install Cursor CLI | ||
| RUN curl -fsSL https://cursor.com/install | bash | ||
|
|
||
| # Install ai-helpers skills, commands, and agents for Cursor | ||
| RUN mkdir -p /home/cursor/.cursor/skills /home/cursor/.cursor/commands && \ | ||
| ln -s /opt/ai-helpers/helpers/skills/* /home/cursor/.cursor/skills/ && \ | ||
| ln -s /opt/ai-helpers/helpers/commands/* /home/cursor/.cursor/commands/ && \ | ||
| ln -s /opt/ai-helpers/helpers/agents/* /home/cursor/.cursor/skills/ | ||
|
|
||
| # Set Cursor Agent CLI as the default command | ||
| # --trust: skip workspace trust prompt | ||
| # --print: output to stdout for non-interactive container use | ||
| ENTRYPOINT ["/home/cursor/.local/bin/agent", "--trust", "--print"] | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π§© Analysis chain
π Script executed:
Repository: opendatahub-io/ai-helpers
Length of output: 780
π Script executed:
Repository: opendatahub-io/ai-helpers
Length of output: 222
π Script executed:
Repository: opendatahub-io/ai-helpers
Length of output: 202
π Script executed:
Repository: opendatahub-io/ai-helpers
Length of output: 770
π Script executed:
Repository: opendatahub-io/ai-helpers
Length of output: 1421
π Script executed:
Repository: opendatahub-io/ai-helpers
Length of output: 1323
π Script executed:
Repository: opendatahub-io/ai-helpers
Length of output: 192
π Script executed:
Repository: opendatahub-io/ai-helpers
Length of output: 371
Major: the PR trigger skips files that are copied into the image.
Both Containerfiles build with
context: .(line 66) and copy the entire repository into/opt/ai-helpers(line 51 in bothimages/cursor/Containerfileandimages/claude/Containerfile), so a PR that only changeshelpers/**,scripts/**,Makefile,categories.yaml, or other files at repository root can modify the image contents while this workflow never runs. The path filter at lines 8-10 only coversimages/**and.github/workflows/build.yml. Remove thepathsfilter or expand it to include all files in the build context.Remediation
pull_request: branches: [ main ] - paths: - - 'images/**' - - '.github/workflows/build.yml'π€ Prompt for AI Agents