Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Release

on:
push:
tags:
- "v*"

permissions:
contents: write

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
MCP_IMAGE_NAME: ${{ github.repository }}-mcp-server

jobs:
release:
name: Create Draft Release
runs-on: ubuntu-latest
steps:
- name: Validate tag format
run: |
TAG="${{ github.ref_name }}"
if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::Invalid tag format: ${TAG}. Expected vMAJOR.MINOR.PATCH (e.g., v0.12.0)"
exit 1
fi
Comment on lines +21 to +27

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Untrusted github.ref_name is expanded into every run: body. GitHub substitutes ${{ ... }} into the script text before the shell runs, and git ref names may contain $, backticks, ;, |, and quotes — so anyone able to push a tag gets arbitrary command execution in a job holding contents: write and persisted push credentials. The tag-format check cannot help, because it is itself written with an interpolated value. Fix by passing the value through env: and quoting the variable in every step.

  • .github/workflows/release.yml#L21-L27: add env: TAG: ${{ github.ref_name }} to the validation step and use if [[ ! "$TAG" =~ ... ]].
  • .github/workflows/release.yml#L34-L37: add the same env: TAG: mapping and drop the inline expansion at Line 37.
  • .github/workflows/release.yml#L47-L53: add TAG: to the existing env: block and call bash hack/release.sh minor --version "$TAG" --force.
  • .github/workflows/release.yml#L55-L61: add TAG: and MINOR_VERSION: ${{ steps.info.outputs.minor_version }} to env: and call bash hack/release.sh patch "$MINOR_VERSION" --version "$TAG" --force.
  • .github/workflows/release.yml#L63-L77: add TAG:, RELEASE_TYPE:, and MINOR_VERSION: to env: and reference the shell variables in the summary block.
🧰 Tools
🪛 zizmor (1.28.0)

[error] 23-23: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

📍 Affects 1 file
  • .github/workflows/release.yml#L21-L27 (this comment)
  • .github/workflows/release.yml#L34-L37
  • .github/workflows/release.yml#L47-L53
  • .github/workflows/release.yml#L55-L61
  • .github/workflows/release.yml#L63-L77
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 21 - 27, Prevent shell injection
from github.ref_name by passing it through step-level env variables instead of
interpolating it in run scripts. In .github/workflows/release.yml#L21-L27, add
TAG from github.ref_name and use "$TAG"; apply the same TAG mapping and remove
inline expansion at `#L34-L37`, `#L47-L53`, and `#L55-L61`, adding MINOR_VERSION where
specified and passing shell variables to hack/release.sh. At `#L63-L77`, add TAG,
RELEASE_TYPE, and MINOR_VERSION to env and use those shell variables in the
summary block.

Source: Linters/SAST tools


- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Determine release type
id: info
run: |
TAG="${{ github.ref_name }}"
PATCH_NUM="${TAG##*.}"
MINOR_VERSION="${TAG%.*}"
if [[ "$PATCH_NUM" == "0" ]]; then
echo "type=minor" >> "$GITHUB_OUTPUT"
else
echo "type=patch" >> "$GITHUB_OUTPUT"
fi
echo "minor_version=${MINOR_VERSION}" >> "$GITHUB_OUTPUT"

- name: Run release script (minor)
if: steps.info.outputs.type == 'minor'
env:
GH_TOKEN: ${{ github.token }}
run: |
chmod +x hack/release.sh
hack/release.sh minor --version "${{ github.ref_name }}" --force

- name: Run release script (patch)
if: steps.info.outputs.type == 'patch'
env:
GH_TOKEN: ${{ github.token }}
run: |
chmod +x hack/release.sh
hack/release.sh patch "${{ steps.info.outputs.minor_version }}" --version "${{ github.ref_name }}" --force

- name: Summary
run: |
TAG="${{ github.ref_name }}"
{
echo "## Draft Release ${TAG}"
echo ""
echo "- **Release**: https://github.com/${{ github.repository }}/releases/tag/${TAG}"
echo "- **Controller image**: \`${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${TAG}\`"
echo "- **MCP server image**: \`${{ env.REGISTRY }}/${{ env.MCP_IMAGE_NAME }}:${TAG}\`"
if [[ "${{ steps.info.outputs.type }}" == "minor" ]]; then
echo "- **Release branch**: \`release-${{ steps.info.outputs.minor_version }}.x\`"
fi
echo ""
echo "> **Note:** This is a draft release. Review the release notes and publish when ready."
} >> "$GITHUB_STEP_SUMMARY"
119 changes: 119 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Local Development Setup

This guide walks you through setting up the Unstructured Data Controller for local development.

## Prerequisites

- Docker
- [Kind](https://kind.sigs.k8s.io/)
- kubectl
- Go
- [yq](https://github.com/mikefarah/yq)
- [AWS CLI](https://aws.amazon.com/cli/) with [awslocal](https://github.com/localstack/awscli-local)
- [Docling](https://github.com/docling-project/docling-serve) (`pip install "docling-serve[ui]"`)
- [Ollama](https://ollama.com/) (for embedding models)

Comment thread
PuneetPunamiya marked this conversation as resolved.
## Quick start (recommended)

Edit these files with your credentials and config before running setup:

- `config/samples/unstructured-secret.yaml` — S3 credentials, embedding endpoint, API keys
- `config/samples/operator_v1alpha1_controllerconfig.yaml` — Docling URL, storage bucket, concurrency

Then run:

```bash
make local-dev-setup
```

This single command:

1. Creates a Kind cluster (`unstructured-data-controller-local`)
2. Creates namespace `unstructured-controller-namespace`
3. Creates the local cache directory
4. Starts Docling (if `docling-serve` is installed)
5. Starts Ollama and pulls the embedding model
6. Starts LocalStack in Docker on `localhost:4566` (container `localstack-dev`)
7. Creates S3 buckets (ingestion, storage, output)
8. Installs CRDs
9. Applies secrets (`operator-secret` and `pipeline-secret`), ControllerConfig, and UnstructuredDataPipeline
10. Runs the controller (`make run`)

Press Ctrl+C to stop the controller. LocalStack and the Kind cluster keep running.

### Subsequent runs

If setup was already done and you only need to run the controller:

```bash
Comment thread
PuneetPunamiya marked this conversation as resolved.
make run
```

Ensure LocalStack is still running:

```bash
curl -sf http://127.0.0.1:4566/_localstack/health
```

If not healthy, start it again:

```bash
./scripts/localstack.sh start
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make local dev should cover till here i think, i will let @concaf chime in

### Cleanup

Remove the full local environment (Docling, Ollama, LocalStack container, cache, Kind cluster):

```bash
make local-dev-cleanup
```

## LocalStack only

To start or manage LocalStack without the full setup:

```bash
./scripts/localstack.sh start # start Docker container
./scripts/localstack.sh setup # create S3 buckets
./scripts/localstack.sh status # health check and resource list
./scripts/localstack.sh stop # stop and remove container
```

View LocalStack API requests:

```bash
docker logs -f localstack-dev
```

See [Setting up LocalStack](docs/setup-localstack.md) for manual setup steps.

## Manual setup

If you prefer step-by-step setup instead of `make local-dev-setup`:

1. [Setting up LocalStack](docs/setup-localstack.md)
2. [Unstructured Data Controller with LocalStack](docs/setup-unstructured-controller.md)

## Verification

```bash
kubectl get controllerconfig controllerconfig -n unstructured-controller-namespace -o yaml
kubectl get unstructureddatapipeline -n unstructured-controller-namespace -o wide
kubectl get sourcecrawler,documentprocessor,chunksgenerator,vectorembeddingsgenerator,destinationsyncer -n unstructured-controller-namespace
```

The ControllerConfig should show `ConfigReady` with `status: "True"`. Pipeline stages should appear after the pipeline is applied.

## Next steps

Follow the [Creating Sample File Guide](docs/creating-sample-file.md) to upload a test file and process it through the pipeline.

## Running e2e tests

E2e tests use in-cluster LocalStack (not the host Docker container). See the test workflow in `.github/workflows/test-e2e.yml`.

```bash
export IMG=<your-image-registry>/<image-name>:<tag>
make docker-build docker-push test-e2e
```
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,21 @@ setup-test-e2e: ## Set up a Kind cluster for e2e tests if it does not exist

.PHONY: test-e2e
test-e2e: setup-test-e2e ## Run the e2e tests. Expected an isolated environment using Kind.
go test -count=1 -tags e2e ./test/e2e/ -v -timeout=60m
KIND_CLUSTER=$(KIND_CLUSTER) SKIP_CLUSTER_SETUP=true go test -count=1 -tags e2e ./test/e2e/ -v -timeout=60m
$(MAKE) cleanup-test-e2e
Comment on lines +145 to 146

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Always clean up the Kind cluster after a failed test run.

A non-zero go test causes Make to stop before line 146, leaving the test cluster behind. Run the test and cleanup in one shell with a captured exit status (or a trap), then return the original test failure.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 145 - 146, Update the e2e test target around the go
test invocation and cleanup-test-e2e to execute both commands in one shell,
capture the go test exit status, always run cleanup even when tests fail, and
return the original test status after cleanup.


.PHONY: cleanup-test-e2e
cleanup-test-e2e: ## Tear down the Kind cluster used for e2e tests
@$(KIND) delete cluster --name $(KIND_CLUSTER)

.PHONY: local-dev-setup
local-dev-setup: ## Full local dev setup (Kind, LocalStack Docker, CRDs, samples, run)
@chmod +x scripts/local-dev-setup.sh && ./scripts/local-dev-setup.sh

.PHONY: local-dev-cleanup
local-dev-cleanup: ## Clean up local development environment
@chmod +x scripts/local-dev-cleanup.sh && ./scripts/local-dev-cleanup.sh

.PHONY: lint
lint: golangci-lint ## Run golangci-lint and yamllint linters
$(GOLANGCI_LINT) run
Expand Down
Loading
Loading