Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
f487d52
Add Rust client SDK POC implementation following RFC-040
jrepp Oct 19, 2025
bde18c7
Update PR status check to handle docs, clients, and code changes sele…
jrepp Oct 19, 2025
ce51e79
Integrate protobuf code generation for gRPC client interfaces
jrepp Oct 19, 2025
ab9d833
Implement gRPC integration for all pattern clients (Producer, Consume…
jrepp Oct 19, 2025
c05db84
Add integration tests and canary test harness for Prism client SDK
jrepp Oct 19, 2025
984c77c
Update changelog with completed Rust client SDK POC implementation
jrepp Oct 19, 2025
063f9a8
Fix Rust lint errors and add canary to docker-compose
jrepp Oct 19, 2025
e891674
Update docker-compose test environment with non-conflicting ports
jrepp Oct 19, 2025
284ef97
Add prism-proxy, prism-admin with network segmentation
jrepp Oct 19, 2025
c8a52b1
Update Docker compose and Dockerfiles to latest format with network s…
jrepp Oct 19, 2025
b3cccd7
Reduce TTL test durations from 5s to 2s with 2s buffers
jrepp Oct 19, 2025
f417c96
Add TTL support to Rust client SDK KeyValue pattern
jrepp Oct 19, 2025
49d4ef7
Document TTL implementation learnings in RFC-040
jrepp Oct 19, 2025
10d19b3
Fix Rust code formatting issues
jrepp Oct 19, 2025
43c5d62
Add protobuf compiler installation to Rust client SDK CI
jrepp Oct 19, 2025
8190be0
Fix shellcheck warnings in GitHub Actions workflows
jrepp Oct 20, 2025
62f2fb6
Fix integration test for lazy connection behavior
jrepp Oct 20, 2025
c3e3e60
Fix doctest return type annotations to use Box<dyn std::error::Error>
jrepp Oct 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@

- name: Install golangci-lint
if: steps.cache-golangci-lint.outputs.cache-hit != 'true'
run: |

Check warning on line 255 in .github/workflows/ci.yml

View workflow job for this annotation

GitHub Actions / Lint GitHub Actions

[actionlint] reported by reviewdog 🐶 shellcheck reported issue in this script: SC2046:warning:2:17: Quote this to prevent word splitting [shellcheck] Raw Output: w:.github/workflows/ci.yml:255:9: shellcheck reported issue in this script: SC2046:warning:2:17: Quote this to prevent word splitting [shellcheck]
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh \
| sh -s -- -b $(go env GOPATH)/bin v2.5.0

Expand Down Expand Up @@ -700,11 +700,11 @@
[[ "${{ needs.validate-docs.result }}" != "success" ]] || \
[[ "${{ needs.build.result }}" != "success" ]]; then
echo "❌ CI pipeline failed"
echo "status=failure" >> $GITHUB_OUTPUT
echo "status=failure" >> "$GITHUB_OUTPUT"
exit 1
else
echo "✅ CI pipeline passed"
echo "status=success" >> $GITHUB_OUTPUT
echo "status=success" >> "$GITHUB_OUTPUT"
fi

- name: send-ntfy-notification
Expand Down
85 changes: 85 additions & 0 deletions .github/workflows/client-sdk-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Client SDK CI

on:
pull_request:
paths:
- 'clients/**'
- '.github/workflows/client-sdk-ci.yml'
push:
branches:
- main
paths:
- 'clients/**'
- '.github/workflows/client-sdk-ci.yml'

# Only allow one client SDK CI run at a time per PR/branch
concurrency:
group: client-sdk-ci-${{ github.ref }}
cancel-in-progress: true

jobs:
rust-client:
name: Rust Client SDK
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt

- name: Install protobuf compiler
run: |
sudo apt-get update
sudo apt-get install -y protobuf-compiler
protoc --version

- name: Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: clients/rust/prism-client

- name: Check formatting
working-directory: clients/rust/prism-client
run: cargo fmt --check

- name: Run clippy
working-directory: clients/rust/prism-client
run: cargo clippy --all-features -- -D warnings

- name: Build
working-directory: clients/rust/prism-client
run: cargo build --verbose

- name: Run tests
working-directory: clients/rust/prism-client
run: cargo test --verbose

- name: Run doctests
working-directory: clients/rust/prism-client
run: cargo test --doc

- name: Build examples
working-directory: clients/rust/prism-client
run: |
cargo build --example hello_world
cargo build --example simple_producer
cargo build --example simple_consumer

# Status check that's required for PR approval
# This aggregates all client SDK checks
client-sdk-status:
name: Client SDK Status Check
runs-on: ubuntu-latest
needs: [rust-client]
if: always()
steps:
- name: Check all jobs status
run: |
if [[ "${{ needs.rust-client.result }}" == "failure" ]]; then
echo "❌ Rust client SDK checks failed"
exit 1
fi
echo "✅ All client SDK checks passed"
4 changes: 2 additions & 2 deletions .github/workflows/docs-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ jobs:
run: |
if [[ "${{ needs.validate-docs.result }}" != "success" ]]; then
echo "❌ Documentation validation failed"
echo "status=failure" >> $GITHUB_OUTPUT
echo "status=failure" >> "$GITHUB_OUTPUT"
exit 1
else
echo "✅ Documentation validation passed"
echo "status=success" >> $GITHUB_OUTPUT
echo "status=success" >> "$GITHUB_OUTPUT"
fi
182 changes: 139 additions & 43 deletions .github/workflows/pr-status-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ jobs:
timeout-minutes: 5
outputs:
docs-only: ${{ steps.changes.outputs.docs-only }}
clients-only: ${{ steps.changes.outputs.clients-only }}
code-changes: ${{ steps.changes.outputs.code-changes }}
has-docs: ${{ steps.changes.outputs.has-docs }}
has-clients: ${{ steps.changes.outputs.has-clients }}

steps:
- name: Checkout
Expand All @@ -41,18 +44,59 @@ jobs:
# Get list of changed files
CHANGED_FILES=$(git diff --name-only "$BASE_REF" HEAD)

# Check if only docs files changed
# Define patterns for different change types
DOCS_PATTERN='(^docs-cms/|^docusaurus/|^tooling/build_docs\.py|^tooling/validate_docs\.py|\.md$|^\.github/workflows/docs)'
CODE_FILES=$(echo "$CHANGED_FILES" | grep -vE "${DOCS_PATTERN}" || true)
CLIENTS_PATTERN='(^clients/|^\.github/workflows/client-sdk-ci\.yml)'

if [ -z "$CODE_FILES" ]; then
echo "docs-only=true" >> $GITHUB_OUTPUT
echo "code-changes=false" >> $GITHUB_OUTPUT
# Categorize changes
DOCS_FILES=$(echo "$CHANGED_FILES" | grep -E "${DOCS_PATTERN}" || true)
CLIENT_FILES=$(echo "$CHANGED_FILES" | grep -E "${CLIENTS_PATTERN}" || true)
OTHER_FILES=$(echo "$CHANGED_FILES" | grep -vE "${DOCS_PATTERN}" | grep -vE "${CLIENTS_PATTERN}" || true)

# Set individual flags
HAS_DOCS="false"
HAS_CLIENTS="false"
HAS_CODE="false"

[ -n "$DOCS_FILES" ] && HAS_DOCS="true"
[ -n "$CLIENT_FILES" ] && HAS_CLIENTS="true"
[ -n "$OTHER_FILES" ] && HAS_CODE="true"

# Output individual flags
{
echo "has-docs=${HAS_DOCS}"
echo "has-clients=${HAS_CLIENTS}"
} >> "$GITHUB_OUTPUT"

# Determine exclusive categories
if [[ "$HAS_DOCS" == "true" && "$HAS_CLIENTS" == "false" && "$HAS_CODE" == "false" ]]; then
{
echo "docs-only=true"
echo "clients-only=false"
echo "code-changes=false"
} >> "$GITHUB_OUTPUT"
echo "📄 Detected: Documentation-only changes"
elif [[ "$HAS_CLIENTS" == "true" && "$HAS_DOCS" == "false" && "$HAS_CODE" == "false" ]]; then
{
echo "docs-only=false"
echo "clients-only=true"
echo "code-changes=false"
} >> "$GITHUB_OUTPUT"
echo "📱 Detected: Client SDK-only changes"
elif [[ "$HAS_CODE" == "true" ]]; then
{
echo "docs-only=false"
echo "clients-only=false"
echo "code-changes=true"
} >> "$GITHUB_OUTPUT"
echo "💻 Detected: Code changes (full CI required)"
else
echo "docs-only=false" >> $GITHUB_OUTPUT
echo "code-changes=true" >> $GITHUB_OUTPUT
echo "💻 Detected: Code changes (CI required)"
{
echo "docs-only=false"
echo "clients-only=false"
echo "code-changes=true"
} >> "$GITHUB_OUTPUT"
echo "🔀 Detected: Mixed changes (full CI required)"
fi

pr-status:
Expand All @@ -70,7 +114,10 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
DOCS_ONLY="${{ needs.detect-changes.outputs.docs-only }}"
CLIENTS_ONLY="${{ needs.detect-changes.outputs.clients-only }}"
CODE_CHANGES="${{ needs.detect-changes.outputs.code-changes }}"
HAS_DOCS="${{ needs.detect-changes.outputs.has-docs }}"
HAS_CLIENTS="${{ needs.detect-changes.outputs.has-clients }}"
SHA="${{ github.event.pull_request.head.sha || github.sha }}"
MAX_WAIT=5400 # 90 minutes in seconds
CHECK_INTERVAL=30 # Check every 30 seconds
Expand All @@ -80,64 +127,113 @@ jobs:
echo "## PR Status Check"
echo ""
echo "- Documentation-only PR: ${DOCS_ONLY}"
echo "- Client SDK-only PR: ${CLIENTS_ONLY}"
echo "- Code changes detected: ${CODE_CHANGES}"
echo "- Has docs changes: ${HAS_DOCS}"
echo "- Has client changes: ${HAS_CLIENTS}"
echo "- Commit SHA: ${SHA}"
echo ""
} >> "$GITHUB_STEP_SUMMARY"

# Determine which check we need to wait for
# Determine which checks we need to wait for
REQUIRED_CHECKS=()

if [[ "$DOCS_ONLY" == "true" ]]; then
REQUIRED_CHECK="Docs Status Check"
WORKFLOW="Docs PR Validation"
REQUIRED_CHECKS+=("Docs Status Check")
echo "📄 Waiting for: Docs Status Check" | tee -a "$GITHUB_STEP_SUMMARY"
elif [[ "$CLIENTS_ONLY" == "true" ]]; then
REQUIRED_CHECKS+=("Client SDK Status Check")
echo "📱 Waiting for: Client SDK Status Check" | tee -a "$GITHUB_STEP_SUMMARY"
elif [[ "$CODE_CHANGES" == "true" ]]; then
REQUIRED_CHECKS+=("CI Status Check")
[[ "$HAS_DOCS" == "true" ]] && REQUIRED_CHECKS+=("Docs Status Check")
[[ "$HAS_CLIENTS" == "true" ]] && REQUIRED_CHECKS+=("Client SDK Status Check")
echo "💻 Waiting for: ${REQUIRED_CHECKS[*]}" | tee -a "$GITHUB_STEP_SUMMARY"
else
REQUIRED_CHECK="CI Status Check"
WORKFLOW="CI"
# Mixed changes, wait for all applicable checks
[[ "$HAS_DOCS" == "true" ]] && REQUIRED_CHECKS+=("Docs Status Check")
[[ "$HAS_CLIENTS" == "true" ]] && REQUIRED_CHECKS+=("Client SDK Status Check")
echo "🔀 Waiting for: ${REQUIRED_CHECKS[*]}" | tee -a "$GITHUB_STEP_SUMMARY"
fi

echo "⏳ Waiting for '$REQUIRED_CHECK' from '$WORKFLOW' workflow..." | tee -a "$GITHUB_STEP_SUMMARY"
# Function to check a single check status
check_status() {
local check_name="$1"
gh api \
"repos/${{ github.repository }}/commits/$SHA/check-runs" \
--jq ".check_runs[] | select(.name == \"$check_name\") | {status: .status, conclusion: .conclusion}" \
2>/dev/null || echo ""
}

# Wait for the check to complete
# Wait for all required checks to complete
while [ $ELAPSED -lt $MAX_WAIT ]; do
# Get check runs for this commit
CHECK_STATUS=$(gh api \
"repos/${{ github.repository }}/commits/$SHA/check-runs" \
--jq ".check_runs[] | select(.name == \"$REQUIRED_CHECK\") | {status: .status, conclusion: .conclusion}" \
2>/dev/null || echo "")

if [ -n "$CHECK_STATUS" ]; then
STATUS=$(echo "$CHECK_STATUS" | jq -r '.status')
CONCLUSION=$(echo "$CHECK_STATUS" | jq -r '.conclusion')

if [[ "$STATUS" == "completed" ]]; then
if [[ "$CONCLUSION" == "success" ]]; then
echo "✅ ${REQUIRED_CHECK} completed successfully" | tee -a "$GITHUB_STEP_SUMMARY"
{
echo ""
echo "**Status: ✅ PASSED**"
} >> "$GITHUB_STEP_SUMMARY"
exit 0
ALL_COMPLETE=true
ALL_SUCCESS=true
PENDING_CHECKS=()

for CHECK_NAME in "${REQUIRED_CHECKS[@]}"; do
CHECK_STATUS=$(check_status "$CHECK_NAME")

if [ -n "$CHECK_STATUS" ]; then
STATUS=$(echo "$CHECK_STATUS" | jq -r '.status')
CONCLUSION=$(echo "$CHECK_STATUS" | jq -r '.conclusion')

if [[ "$STATUS" == "completed" ]]; then
if [[ "$CONCLUSION" != "success" ]]; then
echo "❌ ${CHECK_NAME} failed with conclusion: ${CONCLUSION}" | tee -a "$GITHUB_STEP_SUMMARY"
ALL_SUCCESS=false
fi
else
echo "❌ ${REQUIRED_CHECK} failed with conclusion: ${CONCLUSION}" | tee -a "$GITHUB_STEP_SUMMARY"
{
echo ""
echo "**Status: ❌ FAILED**"
} >> "$GITHUB_STEP_SUMMARY"
exit 1
ALL_COMPLETE=false
PENDING_CHECKS+=("$CHECK_NAME")
fi
else
echo "⏳ Check status: ${STATUS} (waiting...)"
ALL_COMPLETE=false
PENDING_CHECKS+=("$CHECK_NAME (not started)")
fi
done

# Check if we're done
if [[ "$ALL_COMPLETE" == "true" ]]; then
if [[ "$ALL_SUCCESS" == "true" ]]; then
echo "✅ All required checks passed" | tee -a "$GITHUB_STEP_SUMMARY"
{
echo ""
echo "**Status: ✅ PASSED**"
echo ""
echo "Completed checks:"
for CHECK in "${REQUIRED_CHECKS[@]}"; do
echo "- ✅ $CHECK"
done
} >> "$GITHUB_STEP_SUMMARY"
exit 0
else
echo "❌ One or more checks failed" | tee -a "$GITHUB_STEP_SUMMARY"
{
echo ""
echo "**Status: ❌ FAILED**"
} >> "$GITHUB_STEP_SUMMARY"
exit 1
fi
else
echo "⏳ Check not found yet (waiting for workflow to start...)"
fi

# Still waiting
if [ ${#PENDING_CHECKS[@]} -gt 0 ]; then
echo "⏳ Still waiting for: ${PENDING_CHECKS[*]}"
fi

sleep $CHECK_INTERVAL
ELAPSED=$((ELAPSED + CHECK_INTERVAL))
done

echo "❌ Timeout waiting for ${REQUIRED_CHECK} after ${MAX_WAIT} seconds" | tee -a "$GITHUB_STEP_SUMMARY"
echo "❌ Timeout waiting for checks after ${MAX_WAIT} seconds" | tee -a "$GITHUB_STEP_SUMMARY"
{
echo ""
echo "**Status: ❌ TIMEOUT**"
echo ""
echo "Pending checks:"
for CHECK in "${PENDING_CHECKS[@]}"; do
echo "- ⏳ $CHECK"
done
} >> "$GITHUB_STEP_SUMMARY"
exit 1
7 changes: 3 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -150,12 +150,11 @@ WORKDIR /app
COPY --from=builder /build/bin/${SERVICE} /app/

# Create data directory for persistence
# Use the existing nobody user (UID/GID 65534) which exists in Alpine by default
RUN mkdir -p /data && \
addgroup -g 65534 -S appgroup && \
adduser -u 65534 -S appuser -G appgroup && \
chown -R appuser:appgroup /data /app
chown -R nobody:nobody /data /app

USER appuser:appgroup
USER nobody:nobody

EXPOSE 8980 8990

Expand Down
Loading
Loading