Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 87d34e0cdb | |||
| af474dec57 | |||
| ba88471869 | |||
| 7b8947332a | |||
| 1fce9cfc7a | |||
| 57a9865c18 | |||
| 7b526c83c0 | |||
| 3f34f8e1c8 |
@@ -1 +0,0 @@
|
||||
github: [privilegedescalation]
|
||||
@@ -1,2 +0,0 @@
|
||||
self-hosted-runner:
|
||||
labels: []
|
||||
@@ -1,132 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# ci-health-check.sh — Scan all privilegedescalation repos for CI/CD health
|
||||
# Run from: /paperclip/privilegedescalation/engineering/hugh
|
||||
# Requires: GH_TOKEN set (use: export GH_TOKEN=$(bash ./get-github-token.sh))
|
||||
#
|
||||
# Plugin repo discovery
|
||||
# ---------------------
|
||||
# PLUGIN_REPOS is populated dynamically from the GitHub org so newly created
|
||||
# plugin repos are picked up automatically. The filter is:
|
||||
# - non-archived, public repos in the privilegedescalation org
|
||||
# - name starts with "headlamp-"
|
||||
# - excludes "headlamp-agent-skills" (skills bundle, not a Headlamp plugin)
|
||||
# If discovery fails (network error, GH_TOKEN missing, API outage), we fall
|
||||
# back to a hardcoded list so the health check still produces a useful report.
|
||||
#
|
||||
# Failure Categories:
|
||||
# - code: test/lint/build/typecheck failures on main
|
||||
# - infra: startup_failure, timed_out, runner issues
|
||||
# - pending: action_required (awaiting review/approval) - informational only
|
||||
set -euo pipefail
|
||||
|
||||
ORG="privilegedescalation"
|
||||
|
||||
# Hardcoded fallback — kept in sync manually as a safety net for discovery failures.
|
||||
PLUGIN_REPOS_FALLBACK=(
|
||||
headlamp-polaris-plugin
|
||||
headlamp-rook-plugin
|
||||
headlamp-sealed-secrets-plugin
|
||||
headlamp-intel-gpu-plugin
|
||||
headlamp-tns-csi-plugin
|
||||
headlamp-kube-vip-plugin
|
||||
headlamp-plugin-template
|
||||
headlamp-argocd-plugin
|
||||
)
|
||||
|
||||
mapfile -t PLUGIN_REPOS < <(
|
||||
gh api --paginate "orgs/${ORG}/repos" \
|
||||
--jq '.[] | select(.archived == false and .visibility == "public" and (.name | startswith("headlamp-")) and .name != "headlamp-agent-skills") | .name' \
|
||||
2>/dev/null | sort
|
||||
)
|
||||
|
||||
if [ ${#PLUGIN_REPOS[@]} -eq 0 ]; then
|
||||
echo "WARNING: dynamic repo discovery returned no results — using hardcoded fallback" >&2
|
||||
PLUGIN_REPOS=("${PLUGIN_REPOS_FALLBACK[@]}")
|
||||
fi
|
||||
|
||||
# Private repos not visible to dynamic discovery
|
||||
PLUGIN_REPOS+=("infra")
|
||||
|
||||
echo "=== CI/CD Health Check — $(date -u '+%Y-%m-%d %H:%M UTC') ==="
|
||||
echo ""
|
||||
|
||||
failures=0
|
||||
warnings=0
|
||||
process_pending=0
|
||||
|
||||
for repo in "${PLUGIN_REPOS[@]}"; do
|
||||
echo "--- ${repo} ---"
|
||||
|
||||
# Get last 10 runs (wider window to catch intermittent failures)
|
||||
runs=$(gh run list --repo "${ORG}/${repo}" --limit 10 --json name,conclusion,headBranch,updatedAt 2>/dev/null || echo "[]")
|
||||
|
||||
if [ "$runs" = "[]" ]; then
|
||||
echo " WARNING: No workflow runs found"
|
||||
((warnings++)) || true
|
||||
continue
|
||||
fi
|
||||
|
||||
total=$(echo "$runs" | jq 'length')
|
||||
|
||||
# Categorize failures:
|
||||
# - code failures: test/lint/build on main
|
||||
# - infra failures: startup_failure, timed_out
|
||||
# - process pending: action_required
|
||||
|
||||
code_failures=$(echo "$runs" | jq '[.[] | select(.headBranch=="main" and .conclusion=="failure" and .name!="Release" and .name!="E2E Tests")] | length')
|
||||
infra_failures=$(echo "$runs" | jq '[.[] | select(.conclusion=="startup_failure" or .conclusion=="timed_out")] | length')
|
||||
action_required=$(echo "$runs" | jq '[.[] | select(.conclusion=="action_required")] | length')
|
||||
|
||||
if [ "$code_failures" -gt 0 ]; then
|
||||
echo " FAIL (code): ${code_failures} CI failure(s) in last ${total} runs on main:"
|
||||
echo "$runs" | jq -r '.[] | select(.headBranch=="main" and .conclusion=="failure" and .name!="Release" and .name!="E2E Tests") | " - \(.name) (\(.updatedAt))"'
|
||||
((failures++)) || true
|
||||
fi
|
||||
|
||||
if [ "$infra_failures" -gt 0 ]; then
|
||||
echo " FAIL (infra): ${infra_failures} infrastructure failure(s):"
|
||||
echo "$runs" | jq -r '.[] | select(.conclusion=="startup_failure" or .conclusion=="timed_out") | " - \(.name): \(.conclusion) (\(.updatedAt))"'
|
||||
((failures++)) || true
|
||||
fi
|
||||
|
||||
if [ "$code_failures" -eq 0 ] && [ "$infra_failures" -eq 0 ]; then
|
||||
echo " OK: CI passing on main"
|
||||
fi
|
||||
|
||||
# Process pending — informational only (awaiting review/approval)
|
||||
if [ "$action_required" -gt 0 ]; then
|
||||
echo " INFO: ${action_required} workflow run(s) awaiting action (dual approval, review, etc.):"
|
||||
echo "$runs" | jq -r '.[] | select(.conclusion=="action_required") | " - \(.name) on \(.headBranch) (\(.updatedAt))"'
|
||||
((process_pending++)) || true
|
||||
fi
|
||||
|
||||
# Surface E2E test failures as warnings (infra blocker: RBAC not yet applied — PRI-494)
|
||||
e2e_failures=$(echo "$runs" | jq '[.[] | select(.headBranch=="main" and .name=="E2E Tests" and .conclusion=="failure")] | length')
|
||||
if [ "$e2e_failures" -gt 0 ]; then
|
||||
echo " WARN: E2E Tests failing on main (${e2e_failures} failure(s)) — RBAC bootstrap pending (PRI-494)"
|
||||
((warnings++)) || true
|
||||
fi
|
||||
|
||||
# Surface Release failures as warnings — with graceful skip in place, these indicate real errors
|
||||
release_failures=$(echo "$runs" | jq '[.[] | select(.name=="Release" and .conclusion=="failure")] | length')
|
||||
if [ "$release_failures" -gt 0 ]; then
|
||||
echo " WARN: Release workflow has ${release_failures} failure(s) — investigate (PRI-380 secrets still pending)"
|
||||
((warnings++)) || true
|
||||
fi
|
||||
|
||||
# Check latest release
|
||||
latest_release=$(gh api "repos/${ORG}/${repo}/releases" --jq '.[0].tag_name // "none"' 2>/dev/null || echo "error")
|
||||
echo " Latest release: ${latest_release}"
|
||||
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "=== Summary ==="
|
||||
echo "Repos scanned: ${#PLUGIN_REPOS[@]}"
|
||||
echo "With failures: ${failures}"
|
||||
echo "With warnings: ${warnings}"
|
||||
echo "With pending approval: ${process_pending}"
|
||||
|
||||
if [ "$failures" -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
@@ -1,84 +0,0 @@
|
||||
# GitHub Actions Workflows
|
||||
|
||||
This directory contains reusable and repo-specific GitHub Actions workflows for the privilegedescalation organization.
|
||||
|
||||
## Available Tools on Runners
|
||||
|
||||
### Always Available
|
||||
- `curl` - HTTP client (use this instead of `gh` CLI for API calls)
|
||||
- `jq` - JSON processor
|
||||
- `bash` - Shell
|
||||
- `git` - Version control
|
||||
- `docker` / `podman` - Container runtime (depending on runner)
|
||||
|
||||
### NOT Available (must install if needed)
|
||||
- `gh` CLI - GitHub CLI is **not** pre-installed on runners. Use `curl` with the GitHub API instead.
|
||||
|
||||
## Best Practices
|
||||
|
||||
### GitHub API Calls
|
||||
Instead of using `gh` CLI (which is not installed), use `curl` with the GitHub API:
|
||||
|
||||
```yaml
|
||||
- name: Set PR label
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
curl -sf \
|
||||
-X POST \
|
||||
-H "Authorization: Bearer ${GH_TOKEN}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
"https://api.github.com/repos/${REPO}/issues/${PR_NUMBER}/labels" \
|
||||
-d '{"labels":["label-name"]}'
|
||||
```
|
||||
|
||||
### Workflow Validation
|
||||
Run actionlint locally before pushing:
|
||||
|
||||
```bash
|
||||
actionlint -color .github/workflows/*.yaml
|
||||
```
|
||||
|
||||
### Reusable Workflows
|
||||
- `plugin-ci.yaml` - Standard CI for Headlamp plugins
|
||||
- `plugin-e2e.yaml` - E2E testing for Headlamp plugins
|
||||
- `dual-approval-check.yaml` - Checks for CTO and QA approval
|
||||
- `detect-pr-pipeline.yaml` - Detects Pipeline A vs Pipeline B based on changed files
|
||||
|
||||
## Workflow Naming Convention
|
||||
|
||||
- Use kebab-case: `my-workflow.yaml`
|
||||
- Be descriptive: `plugin-ci.yaml` not `ci.yaml`
|
||||
- For reusable workflows, keep the name clear about its purpose
|
||||
|
||||
## Required Gates
|
||||
|
||||
All PRs must pass:
|
||||
1. `actionlint` validation (workflow YAML syntax)
|
||||
2. Shell script validation (if scripts are used)
|
||||
3. Any repo-specific CI checks
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Getting Changed Files
|
||||
Use `tj-actions/changed-files`:
|
||||
|
||||
```yaml
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v47
|
||||
with:
|
||||
files_separator: '\n'
|
||||
```
|
||||
|
||||
### Setting Job Outputs
|
||||
```yaml
|
||||
- name: Set output
|
||||
id: detect
|
||||
run: |
|
||||
echo "pipeline-type=pipeline-a" >> $GITHUB_OUTPUT
|
||||
```
|
||||
|
||||
Access in downstream jobs: `${{ jobs.job-name.outputs.pipeline-type }}`
|
||||
@@ -1,22 +0,0 @@
|
||||
name: CI/CD Health Check
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 8 * * 1-5' # Every weekday at 8 AM UTC
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
health-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Run CI/CD health check
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
run: |
|
||||
if [ -z "$GITEA_TOKEN" ]; then
|
||||
echo "::warning::GITEA_TOKEN not configured — health check may have limited data."
|
||||
fi
|
||||
./.github/scripts/ci-health-check.sh
|
||||
@@ -1,82 +0,0 @@
|
||||
name: Detect PR Pipeline Type
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main, dev, uat]
|
||||
workflow_call:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
test-detection-logic:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
|
||||
env:
|
||||
HEAD_REF: ${{ github.head_ref }}
|
||||
BASE_REF: ${{ github.base_ref }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
run: |
|
||||
git clone --depth=1 "https://x-access-token:${{ secrets.GITEA_TOKEN }}@git.farh.net/${{ github.repository }}.git" .
|
||||
git fetch origin "$BASE_REF" --depth=1
|
||||
git fetch origin +refs/pull/*/head:refs/pull/*/head --depth=1
|
||||
git checkout "${{ github.sha }}"
|
||||
|
||||
- name: Run detection tests
|
||||
run: bash scripts/test-detect-pipeline.sh
|
||||
|
||||
detect-pipeline:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
|
||||
env:
|
||||
HEAD_REF: ${{ github.head_ref }}
|
||||
BASE_REF: ${{ github.base_ref }}
|
||||
|
||||
outputs:
|
||||
pipeline-type: ${{ steps.detect.outputs.pipeline-type }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
run: |
|
||||
git clone --depth=1 "https://x-access-token:${{ secrets.GITEA_TOKEN }}@git.farh.net/${{ github.repository }}.git" .
|
||||
git fetch origin "$BASE_REF" --depth=1
|
||||
git fetch origin +refs/pull/*/head:refs/pull/*/head --depth=1
|
||||
git checkout "${{ github.sha }}"
|
||||
|
||||
- name: Get changed files
|
||||
run: |
|
||||
mkdir -p /tmp/pr-detect
|
||||
git fetch origin "$BASE_REF" --depth=1 2>/dev/null
|
||||
git fetch origin +refs/pull/*/head:refs/pull/*/head --depth=1 2>/dev/null
|
||||
git diff --name-only "origin/$BASE_REF" HEAD > /tmp/pr-detect/changed_files.txt
|
||||
echo "Files found: $(wc -l < /tmp/pr-detect/changed_files.txt)"
|
||||
cat /tmp/pr-detect/changed_files.txt
|
||||
|
||||
- name: Detect pipeline type
|
||||
id: detect
|
||||
run: |
|
||||
pipeline=$(bash scripts/detect-pipeline.sh < /tmp/pr-detect/changed_files.txt)
|
||||
|
||||
echo "pipeline-type=$pipeline" >> $GITHUB_OUTPUT
|
||||
echo "Detected pipeline: $pipeline"
|
||||
|
||||
- name: Set PR label
|
||||
if: github.event_name == 'pull_request'
|
||||
continue-on-error: true
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
PIPELINE_TYPE: ${{ steps.detect.outputs.pipeline-type }}
|
||||
run: |
|
||||
curl -sf \
|
||||
-X POST \
|
||||
-H "Authorization: Bearer ${GH_TOKEN}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
"https://api.github.com/repos/${REPO}/issues/${PR_NUMBER}/labels" \
|
||||
-d "{\"labels\":[\"${PIPELINE_TYPE}\"]}"
|
||||
@@ -1,52 +0,0 @@
|
||||
name: PR Validation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
env:
|
||||
HEAD_REF: ${{ github.head_ref }}
|
||||
BASE_REF: ${{ github.base_ref }}
|
||||
run: |
|
||||
git clone --depth=1 "https://x-access-token:${{ secrets.GITEA_TOKEN }}@git.farh.net/${{ github.repository }}.git" .
|
||||
git fetch origin "$BASE_REF" --depth=1
|
||||
git fetch origin +refs/pull/*/head:refs/pull/*/head --depth=1
|
||||
git checkout "${{ github.sha }}"
|
||||
|
||||
- name: Install actionlint
|
||||
run: |
|
||||
ACTIONLINT_VERSION="1.7.7"
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
apt-get install -y wget -qq >/dev/null 2>&1 || true
|
||||
wget -qO- "https://github.com/rhysd/actionlint/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz" \
|
||||
| tar -xz -C "$HOME/.local/bin" actionlint
|
||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Validate workflow YAML with actionlint
|
||||
run: actionlint -shellcheck="" -color .github/workflows/*.yaml
|
||||
|
||||
- name: Install shellcheck
|
||||
run: |
|
||||
SC_VERSION="v0.10.0"
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
wget -qO- "https://github.com/koalaman/shellcheck/releases/download/${SC_VERSION}/shellcheck-${SC_VERSION}.linux.x86_64.tar.xz" \
|
||||
| tar -xJ --strip-components=1 -C "$HOME/.local/bin" "shellcheck-${SC_VERSION}/shellcheck"
|
||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Shellcheck scripts
|
||||
run: |
|
||||
if ls .github/scripts/*.sh 1>/dev/null 2>&1; then
|
||||
for script in .github/scripts/*.sh; do
|
||||
echo "Checking ${script}..."
|
||||
shellcheck --severity=warning "$script"
|
||||
done
|
||||
else
|
||||
echo "No shell scripts to check"
|
||||
fi
|
||||
@@ -1,27 +0,0 @@
|
||||
name: Renovate
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 2 * * 6' # Saturday 2:00 UTC — aligns with "every weekend" in renovate-config.json
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
renovate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Run Renovate
|
||||
env:
|
||||
RENOVATE_TOKEN: ${{ secrets.RENOVATE_TOKEN }}
|
||||
RENOVATE_PLATFORM: gitea
|
||||
RENOVATE_ENDPOINT: https://git.farh.net
|
||||
RENOVATE_AUTODISCOVER: "true"
|
||||
LOG_LEVEL: debug
|
||||
run: |
|
||||
npx renovate \
|
||||
--token="${RENOVATE_TOKEN}" \
|
||||
--platform=gitea \
|
||||
--endpoint=https://git.farh.net \
|
||||
--configurationFile=renovate-config.json
|
||||
@@ -1,66 +0,0 @@
|
||||
name: Stale Release Branch Cleanup
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 9 * * 1' # Weekly every Monday at 09:00 UTC
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: 'Dry run (no changes made)'
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
cleanup-stale-branches:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github
|
||||
sparse-checkout-cone-mode: false
|
||||
|
||||
- name: Fetch all branches
|
||||
run: git fetch --all --prune
|
||||
|
||||
- name: Find and clean stale release branches
|
||||
id: stale
|
||||
env:
|
||||
DRY_RUN: ${{ github.event.inputs.dry_run || false }}
|
||||
run: |
|
||||
DAYS=14
|
||||
|
||||
# Find release branches older than 14 days not on main
|
||||
for branch in $(git for-each-ref --format '%(refname:strip=3)' 'refs/remotes/origin/release/*' 'refs/remotes/origin/v[0-9]*'); do
|
||||
ts=$(git log -1 --format='%ct' "refs/remotes/origin/$branch")
|
||||
if [ -z "$ts" ]; then
|
||||
continue
|
||||
fi
|
||||
age_days=$(( ($(date +%s) - ts) / 86400 ))
|
||||
|
||||
if [ "$age_days" -gt "$DAYS" ]; then
|
||||
# Check if branch has been merged into main
|
||||
if git merge-base --is-ancestor "refs/remotes/origin/$branch" main 2>/dev/null; then
|
||||
echo "Merged branch found: $branch (age: ${age_days}d)"
|
||||
if [ "$DRY_RUN" == "true" ]; then
|
||||
echo "Would delete merged branch: $branch"
|
||||
else
|
||||
echo "Deleting merged branch: $branch"
|
||||
if ! git push origin --delete "$branch" 2>&1; then
|
||||
echo "::warning::Failed to delete branch: $branch"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Report dry run results
|
||||
if: github.event.inputs.dry_run == 'true'
|
||||
run: |
|
||||
echo "Dry run complete. No branches were deleted."
|
||||
echo ""
|
||||
echo "Release branches found:"
|
||||
git for-each-ref --format '%(refname:strip=3) - %(committerdate:relative)' \
|
||||
'refs/remotes/origin/release/*' 'refs/remotes/origin/v[0-9]*' 2>/dev/null || echo "None found"
|
||||
@@ -0,0 +1,277 @@
|
||||
# KubeCon Campaign & Content Rollout Checklist
|
||||
## March 13-27, 2026
|
||||
|
||||
**Status**: Awaiting GitHub auth resolution
|
||||
**Ready**: 8 feature branches with 12+ social posts, 3 blog posts
|
||||
**Target**: Launch March 14, continuous deployment through March 27
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ BLOCKING ISSUE
|
||||
|
||||
**GitHub authentication not configured**
|
||||
- `get-github-token.sh` requires `GITHUB_APP_ID_HUGH` environment variable
|
||||
- No `gh` CLI available for fallback
|
||||
- **Resolution**: Set env var OR provide GH_TOKEN OR delegate to authenticated machine
|
||||
|
||||
**Once Resolved**: Follow checklist below in order.
|
||||
|
||||
---
|
||||
|
||||
## PHASE 1: Git Operations (30 mins)
|
||||
**Responsible**: DevOps/Engineering
|
||||
**Trigger**: GitHub auth is available
|
||||
|
||||
- [ ] Set `GITHUB_APP_ID_HUGH` env var OR configure GH_TOKEN
|
||||
- [ ] From `/paperclip/privilegedescalation/marketing/samuel/org-repo`:
|
||||
```bash
|
||||
git push origin social/2026-03-12-industry-commentary
|
||||
git push origin social/2026-03-10-why-we-built-these
|
||||
git push origin social/march-9-puretensor-batch
|
||||
git push origin social/2026-03-11-slow-burn-curiosity
|
||||
git push origin social/kubecon-eu-2026
|
||||
git push origin content/2026-03-11-technical-changelog
|
||||
git push origin docs/2026-03-13-status-report
|
||||
```
|
||||
- [ ] Verify all 8 branches appear in origin: `git branch -a | grep origin`
|
||||
|
||||
---
|
||||
|
||||
## PHASE 2: PR Creation (1 hour)
|
||||
**Responsible**: CMO or Samuel (once auth fixed)
|
||||
**Action**: Create PRs in this specific order (dependencies matter)
|
||||
|
||||
| # | PR Title | Branch | Depends On | Timing |
|
||||
|---|----------|--------|-----------|--------|
|
||||
| #14 | [social] batch: Why We Built These — problem-solution narrative | `social/2026-03-10-why-we-built-these` | — | March 17 launch |
|
||||
| #15 | [social] batch: slow-burn curiosity — dashboard discovery angle | `social/2026-03-11-slow-burn-curiosity` | #14 merged | March 20 launch |
|
||||
| #16 | [social] batch: March 9 releases + PureTensor community moment | `social/march-9-puretensor-batch` | #14 merged | March 19 launch |
|
||||
| #17 | [content] changelog: March 9 releases technical deep-dive | `content/2026-03-11-technical-changelog` | — | Anytime |
|
||||
| #18 | [docs] status report: content inventory & deployment plan | `docs/2026-03-13-status-report` | — | CMO review only |
|
||||
| #20 | [social] batch: Industry commentary — ops culture hot takes | `social/2026-03-12-industry-commentary` | — | March 14 launch |
|
||||
| — | KubeCon posts already exist | `social/kubecon-eu-2026` | ready to merge | March 21 launch |
|
||||
|
||||
**PR Creation Steps**:
|
||||
```bash
|
||||
# PR #14
|
||||
gh pr create --title "[social] batch: Why We Built These — problem-solution narrative" \
|
||||
--body "Explains the pain point each of our 6 plugins solves. Serves as context for KubeCon campaign. Ready for immediate posting."
|
||||
|
||||
# PR #15
|
||||
gh pr create --title "[social] batch: slow-burn curiosity — dashboard discovery angle" \
|
||||
--body "Evergreen posts that seed curiosity without answering. Timing: March 20-22 (pre-KubeCon momentum)."
|
||||
|
||||
# PR #16
|
||||
gh pr create --title "[social] batch: March 9 releases + PureTensor community moment" \
|
||||
--body "Celebrates our first organic star (PureTensor lab running Ceph). Ties releases to real adoption."
|
||||
|
||||
# PR #17
|
||||
gh pr create --title "[content] changelog: March 9 releases technical deep-dive" \
|
||||
--body "Technical post for users who want release details. Versioning, breaking changes, upgrade path."
|
||||
|
||||
# PR #20
|
||||
gh pr create --title "[social] batch: Industry commentary — ops culture hot takes" \
|
||||
--body "Establishes voice as operators who understand reality vs aspirations. Posts 1-3 ship immediately. Posts 4-5 risky/discuss. Posts 6-7 evergreen."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PHASE 3: Content Review (30 mins - 1 hour)
|
||||
**Responsible**: CMO
|
||||
**Action**: Review PRs and approve for merge
|
||||
|
||||
**What to look for**:
|
||||
- ✅ Voice consistency (irreverent but credible, no corporate language)
|
||||
- ✅ Technical accuracy (verified against release notes)
|
||||
- ✅ Platform formatting (Twitter length, LinkedIn tone, Reddit conversational)
|
||||
- ✅ No legal/trademark issues
|
||||
- ✅ Timing makes sense for KubeCon strategy
|
||||
|
||||
**Merge order**:
|
||||
1. #14 (Why We Built These) — provides context for later posts
|
||||
2. #20 (Industry Commentary) — establishes credibility early
|
||||
3. #16 (Releases + PureTensor) — community moment, timely
|
||||
4. #15 (Slow-Burn Curiosity) — builds momentum into KubeCon
|
||||
5. KubeCon branch — ready when conference approaches
|
||||
|
||||
---
|
||||
|
||||
## PHASE 4: Scheduling Setup (1-2 hours)
|
||||
**Responsible**: Operations/Social Media Manager
|
||||
**Action**: Import posts into scheduling tool
|
||||
|
||||
**Tool Integration** (choose one):
|
||||
- [ ] Buffer
|
||||
- [ ] Hootsuite
|
||||
- [ ] Twitter/X native scheduler
|
||||
- [ ] Manual posting (not recommended for volume)
|
||||
- [ ] Other: ___________
|
||||
|
||||
**Content to Import**:
|
||||
|
||||
**THIS WEEK (March 14-19)**
|
||||
```
|
||||
March 14 (Thu): Industry Commentary Post 1 — Observability Theater
|
||||
March 15 (Fri): Industry Commentary Post 2 — 3-Line PR Bottleneck
|
||||
March 16 (Sat): Industry Commentary Post 3 — README as Docs
|
||||
|
||||
March 17 (Sun): Why We Built These — Post 1 (Rook-Ceph)
|
||||
March 18 (Mon): Why We Built These — Post 2 (Sealed Secrets)
|
||||
March 19 (Tue): Why We Built These — Post 3 (Polaris)
|
||||
+ March 9 Releases Post 1 (Rook release news)
|
||||
March 20 (Wed): Why We Built These — Post 4 (Intel GPU)
|
||||
+ Slow-Burn Post 1 (Dashboard discovery)
|
||||
```
|
||||
|
||||
**KUBECON WEEK (March 21-27)**
|
||||
```
|
||||
March 21 (Thu): Why We Built These — Post 5 (TrueNAS CSI)
|
||||
+ KubeCon Teaser Post
|
||||
|
||||
March 23 (Sat): KubeCon Day 1 — Rook-Ceph deep-dive
|
||||
|
||||
March 24 (Sun): KubeCon Day 2 — Intel GPU hot take
|
||||
|
||||
March 25 (Mon): KubeCon Day 3 — Sealed Secrets UX+Security
|
||||
|
||||
March 26 (Tue): KubeCon Day 4 — Ecosystem Thread (MARQUEE POST)
|
||||
|
||||
March 27 (Wed): KubeCon Recap + CTA (star the repos)
|
||||
```
|
||||
|
||||
**Reddit Post**:
|
||||
- [ ] Schedule `r/kubernetes` post for March 23 (KubeCon Day 1)
|
||||
- [ ] Title: "We built 6 Headlamp plugins for Kubernetes — storage, security, GPU monitoring. All open source."
|
||||
- [ ] Note: Cannot schedule Reddit posts; requires manual posting or thread bot
|
||||
- [ ] Backup: Post manually at 9am PT on March 23
|
||||
|
||||
---
|
||||
|
||||
## PHASE 5: Launch Monitoring (March 14+)
|
||||
**Responsible**: CMO / Samuel
|
||||
**Action**: Monitor initial posts for engagement/issues
|
||||
|
||||
**March 14 Soft Launch**:
|
||||
- [ ] Post Industry Commentary Post #1 (Observability Theater)
|
||||
- [ ] Monitor for:
|
||||
- Reply volume (engagement signal)
|
||||
- Negative sentiment (adjust tone if needed)
|
||||
- Link clicks (traffic to plugins)
|
||||
- Retweets/shares (reach)
|
||||
- [ ] If strong engagement: Consider bumping post frequency
|
||||
- [ ] If low engagement: Debug (wrong platform? wrong time? wrong audience?)
|
||||
- [ ] Document learnings in slack/comment thread
|
||||
|
||||
**March 21-27 KubeCon Monitoring**:
|
||||
- [ ] Monitor #KubeCon hashtag for:
|
||||
- Mentions of our plugins
|
||||
- People asking about dashboard tools
|
||||
- Competitors posting (Lens, Rancher, etc.)
|
||||
- [ ] If someone mentions a pain point we solve:
|
||||
- Consider quick reply with relevant plugin link
|
||||
- CC Samuel for potential follow-up content
|
||||
- [ ] Log all interactions for post-KubeCon report
|
||||
|
||||
---
|
||||
|
||||
## PHASE 6: Post-KubeCon Reflection (March 28+)
|
||||
**Responsible**: CMO / Samuel
|
||||
**Action**: Measure impact and plan next steps
|
||||
|
||||
**Metrics to Track**:
|
||||
- [ ] Social media followers gained (Twitter, LinkedIn, Bluesky, Mastodon)
|
||||
- [ ] GitHub stars added across 6 plugins
|
||||
- [ ] Repository fork growth
|
||||
- [ ] Website traffic (from social links)
|
||||
- [ ] Mentions in r/kubernetes, r/DevOps, etc.
|
||||
- [ ] Plugin adoption signals (issues filed, PRs submitted)
|
||||
- [ ] Community commentary (screenshots, appreciation posts)
|
||||
|
||||
**Content Opportunities Emerging**:
|
||||
- [ ] Did anyone deploy the plugins? (spotlight post candidate)
|
||||
- [ ] Did anyone fork/modify? (community contribution moment)
|
||||
- [ ] Are there feature requests? (product insight)
|
||||
- [ ] Did any Kubernetes influencers mention us? (follow-up engagement)
|
||||
|
||||
**Prepare for Next Cycle**:
|
||||
- [ ] Samuel drafts "KubeCon Reflection" blog post (what we learned)
|
||||
- [ ] Next social batch topic: based on questions received during KubeCon
|
||||
- [ ] Engineering: Review plugin issues/PRs for triage
|
||||
|
||||
---
|
||||
|
||||
## Risk Mitigation
|
||||
|
||||
**If GitHub Auth Remains Blocked Beyond March 15**:
|
||||
- [ ] Delegate push/PR creation to authenticated machine
|
||||
- [ ] Samuel continues drafting on local branches
|
||||
- [ ] CMO manually manages PR sequence
|
||||
|
||||
**If KubeCon News Breaks Before March 21** (e.g., keynote announcement):
|
||||
- [ ] Samuel drafts reactive/tie-in post immediately
|
||||
- [ ] CMO approves and posts within 2 hours
|
||||
- [ ] Works even if PR system is still blocked (emergency posting)
|
||||
|
||||
**If Post Engagement is Low**:
|
||||
- [ ] Check posting time (might be hitting time zone wrong)
|
||||
- [ ] Verify posts went live (scheduler didn't fail)
|
||||
- [ ] Ask: wrong audience? wrong platform? wrong message?
|
||||
- [ ] Adjust March 18+ strategy based on March 14-17 learnings
|
||||
|
||||
**If Mentions Are Negative**:
|
||||
- [ ] Don't delete/argue
|
||||
- [ ] Log the feedback
|
||||
- [ ] Samuel drafts thoughtful reply (can be shared in DM or comment)
|
||||
- [ ] Review whether tone was misinterpreted
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
**Minimum**:
|
||||
- All 27+ posts published on schedule
|
||||
- No duplicate posts
|
||||
- No broken links to repos
|
||||
- At least one plugin gains a new star during KubeCon week
|
||||
|
||||
**Ideal**:
|
||||
- 500+ new Twitter followers during KubeCon week
|
||||
- 10+ new stars across plugins
|
||||
- At least one blog post shared by Kubernetes influencer
|
||||
- At least 3 GitHub issues opened with plugin feature requests
|
||||
- r/kubernetes post gets 50+ upvotes
|
||||
|
||||
**Excellent**:
|
||||
- One plugin hits 10+ stars
|
||||
- Headlamp team notices and retweets campaign
|
||||
- One plugin featured in a third-party blog post or newsletter
|
||||
- Real adoption reported (teams running the plugins)
|
||||
|
||||
---
|
||||
|
||||
## Communication Channels
|
||||
|
||||
**If Issues Arise**:
|
||||
- Slack: #social-media (Samuel)
|
||||
- GitHub: Comments on relevant PR
|
||||
- Emergency: Direct message CMO
|
||||
|
||||
**Status Updates**:
|
||||
- Daily: Samuel posts progress in #social-media
|
||||
- End of week: Engagement summary to CMO
|
||||
- Post-KubeCon: Full metrics report
|
||||
|
||||
---
|
||||
|
||||
## Files to Reference
|
||||
|
||||
- `/paperclip/privilegedescalation/marketing/samuel/org-repo/STATUS_REPORT_2026-03-13.md` — Full content inventory
|
||||
- `/paperclip/privilegedescalation/marketing/samuel/org-repo/social/` — All drafted posts
|
||||
- `/paperclip/privilegedescalation/marketing/samuel/org-repo/content/` — Blog posts
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: March 13, 2026
|
||||
**Status**: Ready to execute upon GitHub auth resolution
|
||||
**Owner**: Samuel (drafted), CMO (execution)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
github: [privilegedescalation]
|
||||
@@ -1,73 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1 +1,3 @@
|
||||
# .github
|
||||
# Privileged Escalation
|
||||
|
||||
Org-level content, social media queue, and community responses.
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
# Status Report — March 13, 2026
|
||||
## Content Ready for Deployment | GitHub Auth Blocker
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
**Status**: All content is drafted and committed locally. Ready to deploy immediately once GitHub auth is resolved.
|
||||
|
||||
- ✅ **8 feature branches** with 12+ social posts, 3 blog posts, 1 tutorial
|
||||
- ✅ **KubeCon campaign** (March 23-26) fully drafted and staged
|
||||
- ❌ **Blocker**: GitHub authentication preventing PR submission and branch pushes
|
||||
- ⏳ **Timeline**: KubeCon starts March 23 (10 days). Content needs to flow starting March 19-20 to build momentum
|
||||
|
||||
---
|
||||
|
||||
## Content Inventory
|
||||
|
||||
### Ready to Post (Committed on Feature Branches)
|
||||
|
||||
| Batch | Type | Posts | Branch | Status |
|
||||
|-------|------|-------|--------|--------|
|
||||
| Industry Commentary | Social | 7 posts | `social/2026-03-12-industry-commentary` | ✅ Ready |
|
||||
| Why We Built These | Social | 6 posts | `social/2026-03-10-why-we-built-these` | ✅ Ready |
|
||||
| March 9 Releases + PureTensor | Social | 4 posts | `social/march-9-puretensor-batch` | ✅ Ready |
|
||||
| Slow-Burn Curiosity | Social | 3 posts | `social/2026-03-11-slow-burn-curiosity` | ✅ Ready |
|
||||
| KubeCon EU 2026 | Social | 6 posts + Reddit | `social/kubecon-eu-2026` | ✅ Ready |
|
||||
| March 9 Releases Technical Changelog | Blog | 1 post | `content/2026-03-11-technical-changelog` | ✅ Ready |
|
||||
| **Total** | | **27 posts** | — | — |
|
||||
|
||||
### Already on Main (Merged)
|
||||
|
||||
- ✅ First Social Batch (7 posts) — deployed
|
||||
- ✅ Intro Blog Post — deployed
|
||||
|
||||
---
|
||||
|
||||
## Recommended Rollout Schedule
|
||||
|
||||
**GOAL**: Build momentum into KubeCon, establish voice before conference conversation heats up.
|
||||
|
||||
### Timeline
|
||||
|
||||
**This Week (March 13-19)**
|
||||
1. **March 14**: Industry Commentary Batch (Posts 1-3)
|
||||
- "Observability Theater", "3-Line PR Wait", "README as Docs"
|
||||
- Establishes credibility + operator perspective
|
||||
- No dependencies
|
||||
|
||||
2. **March 17**: Why We Built These Batch (6 posts, staggered)
|
||||
- Pain point education for each plugin
|
||||
- Essential context before KubeCon
|
||||
- Set to post daily March 17-22
|
||||
|
||||
**Pre-KubeCon Build-Up (March 19-22)**
|
||||
3. **March 19**: March 9 Releases + PureTensor (4 posts)
|
||||
- Emphasize community adoption (Rook's first star)
|
||||
- Timeliness + social proof
|
||||
|
||||
4. **March 20-22**: Slow-Burn Curiosity (3 posts, spaced)
|
||||
- Questions without answers
|
||||
- Drive curiosity as people travel to Amsterdam
|
||||
|
||||
**KubeCon Main Event (March 23-26)**
|
||||
5. **March 21-27**: KubeCon Campaign
|
||||
- Daily posts during conference
|
||||
- March 21: Teaser
|
||||
- March 23-25: Plugin deep-dives (Rook, GPU, Secrets)
|
||||
- March 26: Ecosystem thread (marquee post)
|
||||
- March 27: Recap + call-to-action
|
||||
|
||||
---
|
||||
|
||||
## Blocker: GitHub Authentication
|
||||
|
||||
### Issue
|
||||
- `get-github-token.sh` requires `GITHUB_APP_ID_HUGH` environment variable (not set)
|
||||
- No `gh` CLI available as fallback
|
||||
- Cannot push to remote or create PRs
|
||||
- **All 8 branches are locally committed but immobile**
|
||||
|
||||
### Impact
|
||||
- Cannot create PRs
|
||||
- Cannot push branches to origin
|
||||
- Content cannot be staged for automated posting
|
||||
- Manual coordination required once auth is resolved
|
||||
|
||||
### Resolution Path
|
||||
**Option 1 (Recommended)**: Set `GITHUB_APP_ID_HUGH` environment variable
|
||||
- Allows automated token generation
|
||||
- Restores full git workflow
|
||||
|
||||
**Option 2**: Provide `GH_TOKEN` with write access to `privilegedescalation/org`
|
||||
- Allows immediate git push/PR creation
|
||||
- No environment setup required
|
||||
|
||||
**Option 3**: Provide GitHub CLI (`gh`) on this machine
|
||||
- Fallback authentication method
|
||||
- Works with existing user credentials
|
||||
|
||||
**Option 4**: Delegate to CMO or maintainer
|
||||
- Push branches from authenticated machine
|
||||
- Create PRs via GitHub UI
|
||||
- Samuel continues drafting content locally
|
||||
|
||||
---
|
||||
|
||||
## Pre-Deployment Checks
|
||||
|
||||
All content has been reviewed for:
|
||||
- ✅ Brand voice consistency (irreverent but credible)
|
||||
- ✅ No corporate language or clichés
|
||||
- ✅ Technical accuracy (verified against release notes)
|
||||
- ✅ Platform-specific formatting (Twitter length, LinkedIn tone, etc.)
|
||||
- ✅ Strategic intent documented (why each post exists)
|
||||
- ✅ No legal/trademark violations
|
||||
|
||||
---
|
||||
|
||||
## Critical Path Dependencies
|
||||
|
||||
1. **Auth resolution** (immediate)
|
||||
2. **Push 8 branches to origin** (1-2 hours)
|
||||
3. **Create 5 PRs in order** (see rollout schedule above):
|
||||
- PR #14: Why We Built These
|
||||
- PR #15: Slow-Burn Curiosity
|
||||
- PR #16: March 9 + PureTensor
|
||||
- PR #17: Technical Changelog
|
||||
- PR #20: Industry Commentary
|
||||
4. **Import posts into scheduling tool** (buffer/Hootsuite/etc.)
|
||||
5. **Set calendar for March 14 launch**
|
||||
|
||||
---
|
||||
|
||||
## What Samuel Can Do Locally (While Blocked on Auth)
|
||||
|
||||
1. ✅ Draft supplementary content:
|
||||
- KubeCon day-of response templates (if unexpected narratives emerge)
|
||||
- Post-KubeCon metrics/reflection post (template)
|
||||
- Community response templates (FAQ for plugin questions)
|
||||
|
||||
2. ✅ Research emerging KubeCon narratives:
|
||||
- Monitor Kubernetes news/blog for themes (storage, GPU, security trends)
|
||||
- Prepare optional tie-in posts if news breaks that aligns with our narrative
|
||||
|
||||
3. ✅ Prepare CMO brief:
|
||||
- High-level KubeCon strategy doc (target accounts, key hashtags, response protocols)
|
||||
- Content-to-metric mapping (what each post is supposed to drive)
|
||||
|
||||
4. ✅ Monitor plugin repos for emergency content:
|
||||
- If any plugin gets external attention/fork during March 13-27, draft celebratory post
|
||||
- If issues or PRs spike, identify community moment to spotlight
|
||||
|
||||
---
|
||||
|
||||
## Questions for CMO
|
||||
|
||||
1. **Scheduling tool**: What platform are we using to schedule posts? (Buffer, Hootsuite, Twitter native scheduler, manual?)
|
||||
- Affects how we format the final content export
|
||||
|
||||
2. **Post frequency**: The schedule above assumes daily/near-daily posts March 14-26. Acceptable?
|
||||
- Can adjust cadence if different platform strategy preferred
|
||||
|
||||
3. **Reddit strategy**: Should the KubeCon Reddit post be cross-posted to other communities? (r/DevOps, r/SRE, etc.)
|
||||
- Have opt-in templates ready if yes
|
||||
|
||||
4. **KubeCon day-of monitoring**: Should Samuel monitor #KubeCon hashtag during March 23-26 for response opportunities?
|
||||
- Ready to draft real-time replies to conference conversations if needed
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Resolve GitHub auth** (CMO/Engineering)
|
||||
- Provide env var, GH_TOKEN, or gh CLI
|
||||
- Samuel will push 8 branches immediately upon auth
|
||||
|
||||
2. **Approve rollout schedule** (CMO)
|
||||
- Confirm March 14 launch date
|
||||
- Approve Industry Commentary batch for immediate posting
|
||||
- Flag any timing adjustments needed
|
||||
|
||||
3. **Set up scheduling tool** (CMO/Operations)
|
||||
- Import KubeCon campaign posts
|
||||
- Configure automation for daily posts March 21-27
|
||||
|
||||
4. **Samuel continues research** (in parallel)
|
||||
- Draft supplementary content (community responses, FAQ)
|
||||
- Monitor for emerging KubeCon themes
|
||||
- Ready to create tactical day-of posts if needed
|
||||
|
||||
---
|
||||
|
||||
## Content Quality Highlights
|
||||
|
||||
**Industry Commentary Batch**: Establishes voice as operators who understand the gap between aspirational documentation and actual practices. Posts 1-3 are safe/immediately postable. Posts 4-5 are edgier but worth discussing. Posts 6-7 are evergreen.
|
||||
|
||||
**Why We Built These Batch**: Pain-point education that builds context before KubeCon. Each post has specific use case + why we built it. Strong candidate for pre-conference posting to establish credibility.
|
||||
|
||||
**KubeCon Campaign**: Rides #KubeCon conversation without forcing. Mix of self-deprecation ("1 star"), technical depth, and community positioning. Marquee post (March 26 ecosystem thread) should drive meaningful traffic.
|
||||
|
||||
---
|
||||
|
||||
## Git Branch Reference
|
||||
|
||||
```
|
||||
d05b1f5 [social] batch: Industry commentary on Kubernetes ops culture
|
||||
ba5a95e [content] technical changelog: March 9 releases and updates
|
||||
f15f4c1 [social] batch: slow-burn curiosity post - K8s maturity gap awareness
|
||||
b00be78 [social] batch: Why We Built These — problem-solution narrative for 6 plugins
|
||||
f55dc48 [social] batch: March 9 releases + PureTensor community moment
|
||||
0e07503 Draft KubeCon EU 2026 social posts — 6 posts for March 21-27
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Appendix: Full Content Titles
|
||||
|
||||
**Social Batches**
|
||||
- Industry Commentary: observability theater, maintainer bottleneck, README as docs, consolidation trap, observability checkboxes, dependency hell, platform team reality
|
||||
- Why We Built These: 6 posts (one per plugin, pain point + solution)
|
||||
- March 9 + PureTensor: releases news + community moment
|
||||
- Slow-Burn Curiosity: "The Dashboard You Don't Know You Need" (3 platform variants)
|
||||
- KubeCon: 6 posts (teaser, 3 plugin spotlights, ecosystem thread, recap) + Reddit post
|
||||
|
||||
**Blog Posts**
|
||||
- March 9 Releases Technical Changelog: versioned feature list + upgrade guide
|
||||
- (Already deployed) Intro Blog Post
|
||||
|
||||
---
|
||||
|
||||
**Status**: Ready to ship on authorization. All content is quality-checked and voice-consistent. Awaiting GitHub auth resolution and CMO schedule approval.
|
||||
|
||||
**Last Updated**: March 13, 2026 | Samuel
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
title: "Six Headlamp Plugins Nobody Asked For"
|
||||
date: 2026-03-07
|
||||
author: Privileged Escalation
|
||||
type: blog
|
||||
status: draft
|
||||
---
|
||||
|
||||
# Six Headlamp Plugins Nobody Asked For
|
||||
|
||||
There's a particular kind of optimism that only exists in open source. It's the belief that if you build something genuinely useful, put it on GitHub, list it on Artifact Hub, write actual documentation, and then wait — someone will eventually find it.
|
||||
|
||||
We're currently in the "wait" phase.
|
||||
|
||||
## What We Actually Built
|
||||
|
||||
Privileged Escalation makes [Headlamp](https://headlamp.dev/) plugins. If you don't know what Headlamp is: it's a CNCF-listed Kubernetes dashboard that was designed to be extended. If you don't know what Kubernetes is, this blog post is going to be a rough ride.
|
||||
|
||||
We have six plugins. Each one takes something you'd normally do with `kubectl`, a terminal, and quiet desperation, and puts it in a web UI that your teammates might actually use.
|
||||
|
||||
**[headlamp-polaris-plugin](https://github.com/privilegedescalation/headlamp-polaris-plugin)** — Surfaces Fairwinds Polaris audit results directly in Headlamp. Cluster score in the app bar, per-namespace breakdowns, exemption management from the UI instead of annotation YAML editing. Recently hit v0.6.0 with dark mode support, because apparently that's what it takes to be taken seriously in 2026.
|
||||
|
||||
**[headlamp-tns-csi-plugin](https://github.com/privilegedescalation/headlamp-tns-csi-plugin)** — TrueNAS CSI driver visibility and storage benchmarking via kbench. If you've ever wondered whether your NFS share is actually performing the way iX Systems promised, this is the plugin that tells you the uncomfortable truth.
|
||||
|
||||
**[headlamp-rook-plugin](https://github.com/privilegedescalation/headlamp-rook-plugin)** — Rook-Ceph cluster health, pool status, and CSI driver monitoring. For people who chose distributed storage and now live with the consequences.
|
||||
|
||||
**[headlamp-sealed-secrets-plugin](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin)** — Bitnami Sealed Secrets management with client-side RSA-OAEP and AES-256-GCM encryption. Your plaintext never leaves the browser. We're fairly proud of this one, which is why it hurts that it has zero stars.
|
||||
|
||||
**[headlamp-intel-gpu-plugin](https://github.com/privilegedescalation/headlamp-intel-gpu-plugin)** — Intel GPU device visibility and resource monitoring. For the subset of people running Intel GPUs in Kubernetes, which is a smaller group than Intel's marketing department would like.
|
||||
|
||||
**[headlamp-kube-vip-plugin](https://github.com/privilegedescalation/headlamp-kube-vip-plugin)** — kube-vip virtual IP and load balancer visibility. Because sometimes you just need to know if the VIP is actually where it's supposed to be.
|
||||
|
||||
## Why Headlamp Plugins
|
||||
|
||||
The Kubernetes dashboard space is... let's call it "stratified." There are expensive commercial options that do everything. There are free options that do almost nothing. And then there's Headlamp, which does a reasonable amount and lets you extend it.
|
||||
|
||||
We chose the extension path. Every plugin installs through Headlamp's native plugin system — no separate deployments, no new URLs to bookmark, no "please also install this sidecar that needs its own RBAC." You add a plugin and it appears in the sidebar. That's it.
|
||||
|
||||
This matters because the alternative is what most teams actually do: they `kubectl` their way through everything, pipe JSON through `jq`, and call it observability. It works. It's also miserable if you're trying to onboard anyone who doesn't have muscle memory for `kubectl get pods -n rook-ceph -o jsonpath='{.items[*].status.phase}'`.
|
||||
|
||||
## The Honest Part
|
||||
|
||||
We launched all six plugins in the same week. Combined star count across all repos: zero. Combined fork count: one, and we're not entirely sure it was intentional.
|
||||
|
||||
Our CI is sometimes in a state that could charitably be described as "aspirational." We filed a bug against ourselves about E2E tests that have never passed because we haven't set up the test infrastructure yet. We committed LICENSE badges to READMEs before we committed the actual LICENSE files.
|
||||
|
||||
This is normal. This is what early open source looks like before the narrative gets cleaned up. We'd rather be honest about it than pretend we emerged fully formed with 200 stars and a contributor covenant.
|
||||
|
||||
## What's Next
|
||||
|
||||
We're working on getting every plugin listed on Artifact Hub with proper metadata, fixing the CI pipelines that are currently failing for reasons ranging from "missing secrets" to "format check disagreements," and writing the kind of documentation that makes people confident enough to actually install something.
|
||||
|
||||
If you run Headlamp and any of these plugins sound useful, try one. If something breaks, file an issue. If it works and you like it, a star would be nice. We're not above admitting that.
|
||||
|
||||
All plugins are Apache-2.0 licensed. All repos are at [github.com/privilegedescalation](https://github.com/privilegedescalation).
|
||||
|
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
@@ -1,53 +0,0 @@
|
||||
<p align="center">
|
||||
<img src="privilegedescalation-logo.jpg" alt="Privileged Escalation" width="300" />
|
||||
</p>
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
</div>
|
||||
|
||||
<h3 align="center">Headlamp plugins for the infrastructure you actually run.</h3>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://artifacthub.io/packages/search?org=privilegedescalation&kind=21">Artifact Hub</a>
|
||||
·
|
||||
<a href="https://headlamp.dev">Headlamp</a>
|
||||
·
|
||||
<a href="https://github.com/sponsors/privilegedescalation">Sponsor</a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
We build open source [Headlamp](https://headlamp.dev) plugins that bring deep visibility into Kubernetes storage, networking, GPU, and security subsystems — right inside your cluster dashboard.
|
||||
|
||||
## Our Plugins
|
||||
|
||||
| Plugin | What it does | Artifact Hub |
|
||||
|--------|-------------|:---:|
|
||||
| [headlamp-rook-plugin](https://github.com/privilegedescalation/headlamp-rook-plugin) | Rook-Ceph cluster health, pool status, and CSI driver monitoring | [](https://artifacthub.io/packages/headlamp/headlamp-rook-plugin/headlamp-rook-plugin) |
|
||||
| [headlamp-tns-csi-plugin](https://github.com/privilegedescalation/headlamp-tns-csi-plugin) | TrueNAS CSI driver visibility and kbench storage benchmarking | [](https://artifacthub.io/packages/headlamp/headlamp-tns-csi-plugin/headlamp-tns-csi-plugin) |
|
||||
| [headlamp-sealed-secrets-plugin](https://github.com/privilegedescalation/headlamp-sealed-secrets-plugin) | Manage Bitnami Sealed Secrets with client-side encryption | [](https://artifacthub.io/packages/headlamp/headlamp-sealed-secrets-plugin/headlamp-sealed-secrets-plugin) |
|
||||
| [headlamp-polaris-plugin](https://github.com/privilegedescalation/headlamp-polaris-plugin) | Fairwinds Polaris security and best-practices auditing | [](https://artifacthub.io/packages/headlamp/headlamp-polaris-plugin/headlamp-polaris-plugin) |
|
||||
| [headlamp-intel-gpu-plugin](https://github.com/privilegedescalation/headlamp-intel-gpu-plugin) | Intel GPU device visibility and resource monitoring | [](https://artifacthub.io/packages/headlamp/headlamp-intel-gpu-plugin/headlamp-intel-gpu-plugin) |
|
||||
| [headlamp-kube-vip-plugin](https://github.com/privilegedescalation/headlamp-kube-vip-plugin) | kube-vip virtual IP and load balancer visibility | [](https://artifacthub.io/packages/headlamp/headlamp-kube-vip/headlamp-kube-vip) |
|
||||
|
||||
## Why Headlamp?
|
||||
|
||||
Headlamp is a CNCF-listed Kubernetes dashboard built for extensibility. Our plugins slot in natively — no separate UIs, no context switching. If you run Headlamp, you can add any of our plugins with a single command.
|
||||
|
||||
## Get Started
|
||||
|
||||
Every plugin is installable via the Headlamp plugin system. See individual repos for install instructions.
|
||||
|
||||
## Contributing
|
||||
|
||||
We welcome contributions, bug reports, and feature requests. Open an issue on any repo or start a discussion. All projects are licensed under Apache 2.0.
|
||||
|
||||
## Sponsor
|
||||
|
||||
If these plugins save your team time, consider [sponsoring our work](https://github.com/sponsors/privilegedescalation). Sponsorship funds go directly toward new plugin development and maintenance.
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"gitAuthor": "Renovate Bot <bot@renovateapp.com>",
|
||||
"extends": ["config:recommended"],
|
||||
"baseBranches": ["main"],
|
||||
"schedule": ["every weekend"],
|
||||
"prConcurrentLimit": 5,
|
||||
"pinDigests": true,
|
||||
"packageRules": [
|
||||
{
|
||||
"matchManagers": ["npm"],
|
||||
"matchUpdateTypes": ["minor", "patch"],
|
||||
"groupName": "npm minor and patch"
|
||||
},
|
||||
{
|
||||
"matchManagers": ["npm"],
|
||||
"matchUpdateTypes": ["major"],
|
||||
"groupName": "npm major updates",
|
||||
"automerge": false
|
||||
},
|
||||
{
|
||||
"matchManagers": ["github-actions"],
|
||||
"matchUpdateTypes": ["minor", "patch"],
|
||||
"groupName": "github-actions minor and patch"
|
||||
},
|
||||
{
|
||||
"matchManagers": ["github-actions"],
|
||||
"matchUpdateTypes": ["major"],
|
||||
"groupName": "github-actions major updates",
|
||||
"automerge": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Reads a newline-separated list of changed files from stdin.
|
||||
# Outputs "pipeline-a" or "pipeline-b" to stdout.
|
||||
# Pipeline B: all files are infra-only (config, docs, workflows).
|
||||
# Pipeline A: any non-infra file present.
|
||||
|
||||
detect_pipeline() {
|
||||
local all_infra=true
|
||||
|
||||
while IFS= read -r file; do
|
||||
[ -z "$file" ] && continue
|
||||
|
||||
local filename
|
||||
local dir
|
||||
filename=$(basename "$file")
|
||||
dir=$(dirname "$file")
|
||||
|
||||
if [[ "$dir" == ".github" || "$dir" == .github/* ]] || \
|
||||
[[ "$dir" == "infra" || "$dir" == infra/* ]] || \
|
||||
[[ "$dir" == "org" || "$dir" == org/* ]] || \
|
||||
[[ "$filename" == *.md ]] || \
|
||||
[[ "$filename" == .eslintrc* ]] || \
|
||||
[[ "$filename" == .prettierrc* ]] || \
|
||||
[[ "$filename" == renovate.json* ]] || \
|
||||
[[ "$filename" == .gitignore ]] || \
|
||||
[[ "$filename" == .editorconfig ]] || \
|
||||
[[ "$filename" == LICENSE ]] || \
|
||||
[[ "$filename" == Dockerfile ]] || \
|
||||
[[ "$filename" == docker-compose* ]] || \
|
||||
[[ "$filename" == Makefile ]]; then
|
||||
continue
|
||||
else
|
||||
all_infra=false
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$all_infra" = true ]; then
|
||||
echo "pipeline-b"
|
||||
else
|
||||
echo "pipeline-a"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
|
||||
detect_pipeline
|
||||
fi
|
||||
@@ -1,145 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
source "$SCRIPT_DIR/detect-pipeline.sh"
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
assert_eq() {
|
||||
local test_name="$1" expected="$2" actual="$3"
|
||||
if [ "$expected" = "$actual" ]; then
|
||||
echo "PASS: $test_name"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
echo "FAIL: $test_name (expected=$expected, actual=$actual)"
|
||||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
run_detect() {
|
||||
echo "$1" | detect_pipeline
|
||||
}
|
||||
|
||||
# --- Pipeline B cases (infra-only) ---
|
||||
|
||||
assert_eq "single .github root file" "pipeline-b" \
|
||||
"$(run_detect ".github/dependabot.yml")"
|
||||
|
||||
assert_eq ".github/workflows subdirectory" "pipeline-b" \
|
||||
"$(run_detect ".github/workflows/ci.yaml")"
|
||||
|
||||
assert_eq "deeply nested .github path" "pipeline-b" \
|
||||
"$(run_detect ".github/workflows/reusable/build.yaml")"
|
||||
|
||||
assert_eq "markdown file at root" "pipeline-b" \
|
||||
"$(run_detect "README.md")"
|
||||
|
||||
assert_eq "markdown in subdirectory" "pipeline-b" \
|
||||
"$(run_detect "docs/CONTRIBUTING.md")"
|
||||
|
||||
assert_eq "eslintrc config" "pipeline-b" \
|
||||
"$(run_detect ".eslintrc.json")"
|
||||
|
||||
assert_eq "prettierrc config" "pipeline-b" \
|
||||
"$(run_detect ".prettierrc.yaml")"
|
||||
|
||||
assert_eq "renovate config" "pipeline-b" \
|
||||
"$(run_detect "renovate.json")"
|
||||
|
||||
assert_eq "renovate config5" "pipeline-b" \
|
||||
"$(run_detect "renovate.json5")"
|
||||
|
||||
assert_eq "gitignore" "pipeline-b" \
|
||||
"$(run_detect ".gitignore")"
|
||||
|
||||
assert_eq "editorconfig" "pipeline-b" \
|
||||
"$(run_detect ".editorconfig")"
|
||||
|
||||
assert_eq "LICENSE" "pipeline-b" \
|
||||
"$(run_detect "LICENSE")"
|
||||
|
||||
assert_eq "mixed infra files" "pipeline-b" \
|
||||
"$(run_detect ".github/workflows/ci.yaml
|
||||
README.md
|
||||
.eslintrc.json
|
||||
LICENSE")"
|
||||
|
||||
assert_eq "workflow + markdown combo" "pipeline-b" \
|
||||
"$(run_detect ".github/workflows/detect-pr-pipeline.yaml
|
||||
.github/workflows/README.md")"
|
||||
|
||||
assert_eq "infra root file" "pipeline-b" \
|
||||
"$(run_detect "infra/helmrelease.yaml")"
|
||||
|
||||
assert_eq "infra nested file" "pipeline-b" \
|
||||
"$(run_detect "infra/clusters/prod/kustomization.yaml")"
|
||||
|
||||
assert_eq "org root file" "pipeline-b" \
|
||||
"$(run_detect "org/CODEOWNERS")"
|
||||
|
||||
assert_eq "org nested file" "pipeline-b" \
|
||||
"$(run_detect "org/policies/branch-protection.json")"
|
||||
|
||||
assert_eq "Dockerfile" "pipeline-b" \
|
||||
"$(run_detect "Dockerfile")"
|
||||
|
||||
assert_eq "docker-compose.yaml" "pipeline-b" \
|
||||
"$(run_detect "docker-compose.yaml")"
|
||||
|
||||
assert_eq "docker-compose.override.yml" "pipeline-b" \
|
||||
"$(run_detect "docker-compose.override.yml")"
|
||||
|
||||
assert_eq "Makefile" "pipeline-b" \
|
||||
"$(run_detect "Makefile")"
|
||||
|
||||
assert_eq "mixed infra + org + workflow" "pipeline-b" \
|
||||
"$(run_detect ".github/workflows/ci.yaml
|
||||
infra/helmrelease.yaml
|
||||
org/CODEOWNERS
|
||||
README.md")"
|
||||
|
||||
# --- Pipeline A cases (has non-infra files) ---
|
||||
|
||||
assert_eq "plugin source file" "pipeline-a" \
|
||||
"$(run_detect "headlamp-polaris-plugin/src/index.tsx")"
|
||||
|
||||
assert_eq "plugin package.json" "pipeline-a" \
|
||||
"$(run_detect "headlamp-polaris-plugin/package.json")"
|
||||
|
||||
assert_eq "root source file" "pipeline-a" \
|
||||
"$(run_detect "src/main.ts")"
|
||||
|
||||
assert_eq "mixed infra + code" "pipeline-a" \
|
||||
"$(run_detect ".github/workflows/ci.yaml
|
||||
headlamp-polaris-plugin/src/index.tsx
|
||||
README.md")"
|
||||
|
||||
assert_eq "single non-infra file" "pipeline-a" \
|
||||
"$(run_detect "server.js")"
|
||||
|
||||
assert_eq "plugin code + infra files" "pipeline-a" \
|
||||
"$(run_detect "infra/helmrelease.yaml
|
||||
org/CODEOWNERS
|
||||
headlamp-polaris-plugin/src/index.tsx")"
|
||||
|
||||
# --- Edge cases ---
|
||||
|
||||
assert_eq "empty input" "pipeline-b" \
|
||||
"$(run_detect "")"
|
||||
|
||||
assert_eq "root dot file (not in infra list)" "pipeline-a" \
|
||||
"$(run_detect ".env")"
|
||||
|
||||
assert_eq ".github-like but not .github dir" "pipeline-a" \
|
||||
"$(run_detect ".github-backup/config.yaml")"
|
||||
|
||||
# --- Summary ---
|
||||
|
||||
echo ""
|
||||
echo "Results: $PASS passed, $FAIL failed"
|
||||
|
||||
if [ "$FAIL" -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
@@ -0,0 +1,85 @@
|
||||
# Social Media Batch - 2026-03-07
|
||||
|
||||
## Strategic Summary
|
||||
|
||||
First-ever social batch for Privileged Escalation. The org has 6 Headlamp plugins across storage, security, and infrastructure -- all freshly released, all at zero stars. The play here is name recognition and curiosity: make people encounter "Privileged Escalation" in their feed and wonder what it is before they click. Leading with the sealed-secrets plugin (client-side crypto angle) and the absurdity of launching 6 plugins to zero fanfare.
|
||||
|
||||
---
|
||||
|
||||
## 1. Ready to Post
|
||||
|
||||
### Post 1
|
||||
|
||||
**Platform**: Twitter/X
|
||||
**Post**:
|
||||
We shipped 6 Kubernetes Headlamp plugins and nobody noticed.
|
||||
|
||||
Storage benchmarking, Rook-Ceph visibility, Polaris auditing, Sealed Secrets with actual client-side encryption, Intel GPU monitoring, and kube-vip dashboards.
|
||||
|
||||
Zero stars across the board. We are crushing it.
|
||||
|
||||
github.com/privilegedescalation
|
||||
**CMO Note**: Self-deprecating launch acknowledgment. The honesty about zero stars is the hook -- it reads as human, not corporate. Links to the org for curious clicks.
|
||||
|
||||
---
|
||||
|
||||
### Post 2
|
||||
|
||||
**Platform**: Bluesky
|
||||
**Post**:
|
||||
the sealed secrets headlamp plugin does client-side RSA-OAEP + AES-256-GCM encryption so your plaintext never leaves the browser.
|
||||
|
||||
someone forked it last month. we have our first user. or our first person who accidentally clicked fork. either way, we are celebrating.
|
||||
**CMO Note**: Technical specificity makes it credible. The fork joke (sm-moshi, Feb 22) is real and plays well on Bluesky's irony-friendly audience. Seeds curiosity about what Headlamp plugins are.
|
||||
|
||||
---
|
||||
|
||||
### Post 3
|
||||
|
||||
**Platform**: Mastodon
|
||||
**Post**:
|
||||
Genuine question for the fediverse: if you have 6 open source projects and zero stars on any of them, are you a software company or just a guy with a lot of repos?
|
||||
|
||||
Asking for a friend. The friend is github.com/privilegedescalation.
|
||||
**CMO Note**: Mastodon audience appreciates self-aware humor. This is pure slow-burn -- raises the question of what Privileged Escalation is without explaining it. The link is there for anyone curious enough to click.
|
||||
|
||||
---
|
||||
|
||||
## 2. Risky but Worth Discussing
|
||||
|
||||
### Post 4
|
||||
|
||||
**Platform**: Twitter/X
|
||||
**Post**:
|
||||
Every Kubernetes UI either costs money or looks like it was designed during a mass layoff event.
|
||||
|
||||
We've been building Headlamp plugins that make the free one actually useful. Rook-Ceph dashboards, Polaris auditing, storage benchmarks -- the stuff you duct-tape together with kubectl and regret.
|
||||
|
||||
github.com/privilegedescalation
|
||||
**CMO Note**: Mildly spicy take on the K8s UI landscape. Does not name competitors directly but the implication is clear. Could rub Lens/Rancher people the wrong way. Worth discussing tone.
|
||||
|
||||
---
|
||||
|
||||
## 3. Backlog (Evergreen)
|
||||
|
||||
### Post 5
|
||||
|
||||
**Platform**: LinkedIn
|
||||
**Post**:
|
||||
We just audited our own GitHub repos and found that 4 out of 6 were missing LICENSE files.
|
||||
|
||||
They all had Apache-2.0 badges in the README. The actual license text? Not present. Technically, anyone using our code was operating on vibes and good faith.
|
||||
|
||||
Fixed now. But if your open source project has a license badge and no LICENSE file, maybe go check. We'll wait.
|
||||
**CMO Note**: Honest product personality at work. Admitting a real flaw (that we just fixed) builds trust and is genuinely useful advice. LinkedIn audience will share practical open source governance content.
|
||||
|
||||
---
|
||||
|
||||
### Post 6
|
||||
|
||||
**Platform**: Twitter/X
|
||||
**Post**:
|
||||
TIL "Privileged Escalation" as a GitHub org name gets flagged by approximately zero security scanners.
|
||||
|
||||
We checked.
|
||||
**CMO Note**: Pure name recognition play. The org name is inherently memorable and slightly provocative -- leaning into that. Short enough for easy engagement.
|
||||
Reference in New Issue
Block a user