Skip to content

Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running #106

Description

@ineedjet

Problem

#102 built the tooling (release automation, vaults//targets/ manifests,
ansible/deploy.yml) to deploy Rybbit for rubykatzen.com on hawkeye
through flightdeck's own pipeline, but it never got to a live deploy — the
PR's own Verification checklist left these unchecked:

  • Publish the first real Hawkeye env asset after external prerequisites
    are configured
  • Run the first real Hawkeye deployment

Nothing has run against production yet, and the prerequisites listed in
#102's PR description haven't been confirmed as actually configured.

Prerequisites to configure (from #102's PR description)

  • GitHub Secret DEPLOY_SSH_PRIVATE_KEY
  • GitHub Secret HAWKEYE_AGE_PRIVATE_KEYnew prerequisite, added
    when decryption and config rendering moved from hawkeye itself to the
    CI runner (Consider decrypting vaults on the CI runner instead of server-side #116, done alongside Consider migrating ansible/deploy.yml to Fabric (Python) #111/One vault per app: drop the APPS_/{app}_ prefix convention for vault-sourced env #114). Content is the private
    key matching keys/hawkeye.pub (previously only ever needed
    server-side, in ~/.config/sops/age/keys.txt; now needed here
    instead, not there).
  • GitHub Variable TAILSCALE_OAUTH_CLIENT_ID and Secret
    TAILSCALE_OAUTH_SECRET (if Tailscale is used to reach hawkeye)
  • Every GitHub Secret/Variable referenced by vaults/hawkeye-traefik.yml's
    and vaults/hawkeye-rybbit.yml's env: mappings: RUBYKATZEN_COM_DOMAIN,
    RUBYKATZEN_COM_ADMIN_MAIL, RUBYKATZEN_COM_CERT_RESOLVER,
    RUBYKATZEN_COM_CLOUDFLARE_TOKEN, RUBYKATZEN_COM_DATABASE_PASSWORD,
    RUBYKATZEN_COM_KEY_HEX_32, RUBYKATZEN_COM_TRAEFIK_HTTP_PORT,
    RUBYKATZEN_COM_TRAEFIK_HTTPS_PORT
  • Server-side rubykatzen-com user on hawkeye, with SSH access matching
    DEPLOY_SSH_PRIVATE_KEY. No longer needed on the server: the age
    private key, sops, gh — all moved to the CI runner side (Consider decrypting vaults on the CI runner instead of server-side #116).
    Docker and Docker Compose are the only remaining host dependencies.
  • External Cloudflare Tunnel configuration for rubykatzen.com
  • Separate open question, not blocking: apps/traefik/docker-compose.yml
    carries the Watchtower label, but hawkeye's apps doesn't include a
    watchtower app — as implemented, the automated deploy path would
    never actually run docker compose up for traefik. Needs its own
    decision (add watchtower to hawkeye's apps, or drop the label)
    before the first real deploy.

Once prerequisites are in place

  • Publish the first real hawkeye.sops.env asset (via a real release,
    or by manually running the encrypt-vaults/encrypt jobs)
  • Run the first real deployment to hawkeye (deploy.yml
    workflow_dispatch, or let it ride the next real release)
  • Confirm traefik + rybbit actually come up and rubykatzen.com
    resolves correctly end to end

Separately: triage currently failing/blocked workflow runs on main

Found while checking the post-merge state of #102.

  • Releaseaction_required, zero jobs ran, on every push to main
    through 1f6117d. Root cause confirmed: repo Settings → Actions →
    General → Workflow permissions was set to "Read repository contents
    and packages permissions" — a hard cap that release.yml's own
    explicit permissions: contents: write / issues: write / pull-requests: write block could not exceed (proven by the fact it
    stayed blocked despite already declaring those permissions itself).
    Fixed by switching to "Read and write permissions" + "Allow GitHub
    Actions to create and approve pull requests" (needed separately for
    release-please's own release PR creation). Confirmed via API
    (default_workflow_permissions: "write",
    can_approve_pull_request_reviews: true). Couldn't force a live
    re-run (gh run rerun refuses runs that never started any jobs, and
    release.yml has no workflow_dispatch) — will get a real
    confirmation on the next push to main / next release-please cycle.
  • Notify Telegram PRstartup_failure on every single run
    (push, PR, and daily schedule) back through history. Same root
    cause: the GitHub error banner named it exactly — nested job
    notify requesting pull-requests: read while the repo only
    allowed pull-requests: none. Fixed by the same Settings change.
    Confirmed live via manual workflow_dispatch after the fix —
    run succeeded.
  • Dependabot update-check runs ("pip in /.", "bundler in /.") on
    58d431e — both failure. Not yet investigated; may or may not be
    the same permissions root cause (worth a quick check next).

Related

Follow-up from #102.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      , 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
       blocks
      (function() {
      function addCopyButtons() {
      document.querySelectorAll('pre code').forEach(function(codeBlock) {
      if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
      codeBlock.parentElement.setAttribute('data-copy-added', 'true');
      var btn = document.createElement('button');
      btn.textContent = 'Copy';
      btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
      btn.onmouseover = function() { this.style.opacity = '1'; };
      btn.onmouseout = function() { this.style.opacity = '0.7'; };
      btn.onclick = function() {
      navigator.clipboard.writeText(codeBlock.textContent).then(function() {
      btn.textContent = 'Copied!';
      setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
      });
      };
      codeBlock.parentElement.style.position = 'relative';
      codeBlock.parentElement.appendChild(btn);
      });
      }
      addCopyButtons();
      // Re-run on dynamic content
      var observer = new MutationObserver(addCopyButtons);
      observer.observe(document.body, { childList: true, subtree: true });
      })();
      }
      } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
      })();
      (function(){
      try {
      var __m = "github.com";
      var __re = new RegExp('^' + "github\\.com" + '
      Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running · Issue #106 · rubykatzen/flightdeck · GitHub
      Skip to content

      Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running #106

      Description

      @ineedjet

      Problem

      #102 built the tooling (release automation, vaults//targets/ manifests,
      ansible/deploy.yml) to deploy Rybbit for rubykatzen.com on hawkeye
      through flightdeck's own pipeline, but it never got to a live deploy — the
      PR's own Verification checklist left these unchecked:

      • Publish the first real Hawkeye env asset after external prerequisites
        are configured
      • Run the first real Hawkeye deployment

      Nothing has run against production yet, and the prerequisites listed in
      #102's PR description haven't been confirmed as actually configured.

      Prerequisites to configure (from #102's PR description)

      • GitHub Secret DEPLOY_SSH_PRIVATE_KEY
      • GitHub Secret HAWKEYE_AGE_PRIVATE_KEYnew prerequisite, added
        when decryption and config rendering moved from hawkeye itself to the
        CI runner (Consider decrypting vaults on the CI runner instead of server-side #116, done alongside Consider migrating ansible/deploy.yml to Fabric (Python) #111/One vault per app: drop the APPS_/{app}_ prefix convention for vault-sourced env #114). Content is the private
        key matching keys/hawkeye.pub (previously only ever needed
        server-side, in ~/.config/sops/age/keys.txt; now needed here
        instead, not there).
      • GitHub Variable TAILSCALE_OAUTH_CLIENT_ID and Secret
        TAILSCALE_OAUTH_SECRET (if Tailscale is used to reach hawkeye)
      • Every GitHub Secret/Variable referenced by vaults/hawkeye-traefik.yml's
        and vaults/hawkeye-rybbit.yml's env: mappings: RUBYKATZEN_COM_DOMAIN,
        RUBYKATZEN_COM_ADMIN_MAIL, RUBYKATZEN_COM_CERT_RESOLVER,
        RUBYKATZEN_COM_CLOUDFLARE_TOKEN, RUBYKATZEN_COM_DATABASE_PASSWORD,
        RUBYKATZEN_COM_KEY_HEX_32, RUBYKATZEN_COM_TRAEFIK_HTTP_PORT,
        RUBYKATZEN_COM_TRAEFIK_HTTPS_PORT
      • Server-side rubykatzen-com user on hawkeye, with SSH access matching
        DEPLOY_SSH_PRIVATE_KEY. No longer needed on the server: the age
        private key, sops, gh — all moved to the CI runner side (Consider decrypting vaults on the CI runner instead of server-side #116).
        Docker and Docker Compose are the only remaining host dependencies.
      • External Cloudflare Tunnel configuration for rubykatzen.com
      • Separate open question, not blocking: apps/traefik/docker-compose.yml
        carries the Watchtower label, but hawkeye's apps doesn't include a
        watchtower app — as implemented, the automated deploy path would
        never actually run docker compose up for traefik. Needs its own
        decision (add watchtower to hawkeye's apps, or drop the label)
        before the first real deploy.

      Once prerequisites are in place

      • Publish the first real hawkeye.sops.env asset (via a real release,
        or by manually running the encrypt-vaults/encrypt jobs)
      • Run the first real deployment to hawkeye (deploy.yml
        workflow_dispatch, or let it ride the next real release)
      • Confirm traefik + rybbit actually come up and rubykatzen.com
        resolves correctly end to end

      Separately: triage currently failing/blocked workflow runs on main

      Found while checking the post-merge state of #102.

      • Releaseaction_required, zero jobs ran, on every push to main
        through 1f6117d. Root cause confirmed: repo Settings → Actions →
        General → Workflow permissions was set to "Read repository contents
        and packages permissions" — a hard cap that release.yml's own
        explicit permissions: contents: write / issues: write / pull-requests: write block could not exceed (proven by the fact it
        stayed blocked despite already declaring those permissions itself).
        Fixed by switching to "Read and write permissions" + "Allow GitHub
        Actions to create and approve pull requests" (needed separately for
        release-please's own release PR creation). Confirmed via API
        (default_workflow_permissions: "write",
        can_approve_pull_request_reviews: true). Couldn't force a live
        re-run (gh run rerun refuses runs that never started any jobs, and
        release.yml has no workflow_dispatch) — will get a real
        confirmation on the next push to main / next release-please cycle.
      • Notify Telegram PRstartup_failure on every single run
        (push, PR, and daily schedule) back through history. Same root
        cause: the GitHub error banner named it exactly — nested job
        notify requesting pull-requests: read while the repo only
        allowed pull-requests: none. Fixed by the same Settings change.
        Confirmed live via manual workflow_dispatch after the fix —
        run succeeded.
      • Dependabot update-check runs ("pip in /.", "bundler in /.") on
        58d431e — both failure. Not yet investigated; may or may not be
        the same permissions root cause (worth a quick check next).

      Related

      Follow-up from #102.

      Metadata

      Metadata

      Assignees

      No one assigned

        Labels

        No labels
        No labels

        Type

        No type

        Projects

        No projects

          Milestone

          No milestone

          Relationships

          None yet

          Development

          No branches or pull requests

          Issue actions

          , 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running · Issue #106 · rubykatzen/flightdeck · GitHub
          Skip to content

          Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running #106

          Description

          @ineedjet

          Problem

          #102 built the tooling (release automation, vaults//targets/ manifests,
          ansible/deploy.yml) to deploy Rybbit for rubykatzen.com on hawkeye
          through flightdeck's own pipeline, but it never got to a live deploy — the
          PR's own Verification checklist left these unchecked:

          • Publish the first real Hawkeye env asset after external prerequisites
            are configured
          • Run the first real Hawkeye deployment

          Nothing has run against production yet, and the prerequisites listed in
          #102's PR description haven't been confirmed as actually configured.

          Prerequisites to configure (from #102's PR description)

          • GitHub Secret DEPLOY_SSH_PRIVATE_KEY
          • GitHub Secret HAWKEYE_AGE_PRIVATE_KEYnew prerequisite, added
            when decryption and config rendering moved from hawkeye itself to the
            CI runner (Consider decrypting vaults on the CI runner instead of server-side #116, done alongside Consider migrating ansible/deploy.yml to Fabric (Python) #111/One vault per app: drop the APPS_/{app}_ prefix convention for vault-sourced env #114). Content is the private
            key matching keys/hawkeye.pub (previously only ever needed
            server-side, in ~/.config/sops/age/keys.txt; now needed here
            instead, not there).
          • GitHub Variable TAILSCALE_OAUTH_CLIENT_ID and Secret
            TAILSCALE_OAUTH_SECRET (if Tailscale is used to reach hawkeye)
          • Every GitHub Secret/Variable referenced by vaults/hawkeye-traefik.yml's
            and vaults/hawkeye-rybbit.yml's env: mappings: RUBYKATZEN_COM_DOMAIN,
            RUBYKATZEN_COM_ADMIN_MAIL, RUBYKATZEN_COM_CERT_RESOLVER,
            RUBYKATZEN_COM_CLOUDFLARE_TOKEN, RUBYKATZEN_COM_DATABASE_PASSWORD,
            RUBYKATZEN_COM_KEY_HEX_32, RUBYKATZEN_COM_TRAEFIK_HTTP_PORT,
            RUBYKATZEN_COM_TRAEFIK_HTTPS_PORT
          • Server-side rubykatzen-com user on hawkeye, with SSH access matching
            DEPLOY_SSH_PRIVATE_KEY. No longer needed on the server: the age
            private key, sops, gh — all moved to the CI runner side (Consider decrypting vaults on the CI runner instead of server-side #116).
            Docker and Docker Compose are the only remaining host dependencies.
          • External Cloudflare Tunnel configuration for rubykatzen.com
          • Separate open question, not blocking: apps/traefik/docker-compose.yml
            carries the Watchtower label, but hawkeye's apps doesn't include a
            watchtower app — as implemented, the automated deploy path would
            never actually run docker compose up for traefik. Needs its own
            decision (add watchtower to hawkeye's apps, or drop the label)
            before the first real deploy.

          Once prerequisites are in place

          • Publish the first real hawkeye.sops.env asset (via a real release,
            or by manually running the encrypt-vaults/encrypt jobs)
          • Run the first real deployment to hawkeye (deploy.yml
            workflow_dispatch, or let it ride the next real release)
          • Confirm traefik + rybbit actually come up and rubykatzen.com
            resolves correctly end to end

          Separately: triage currently failing/blocked workflow runs on main

          Found while checking the post-merge state of #102.

          • Releaseaction_required, zero jobs ran, on every push to main
            through 1f6117d. Root cause confirmed: repo Settings → Actions →
            General → Workflow permissions was set to "Read repository contents
            and packages permissions" — a hard cap that release.yml's own
            explicit permissions: contents: write / issues: write / pull-requests: write block could not exceed (proven by the fact it
            stayed blocked despite already declaring those permissions itself).
            Fixed by switching to "Read and write permissions" + "Allow GitHub
            Actions to create and approve pull requests" (needed separately for
            release-please's own release PR creation). Confirmed via API
            (default_workflow_permissions: "write",
            can_approve_pull_request_reviews: true). Couldn't force a live
            re-run (gh run rerun refuses runs that never started any jobs, and
            release.yml has no workflow_dispatch) — will get a real
            confirmation on the next push to main / next release-please cycle.
          • Notify Telegram PRstartup_failure on every single run
            (push, PR, and daily schedule) back through history. Same root
            cause: the GitHub error banner named it exactly — nested job
            notify requesting pull-requests: read while the repo only
            allowed pull-requests: none. Fixed by the same Settings change.
            Confirmed live via manual workflow_dispatch after the fix —
            run succeeded.
          • Dependabot update-check runs ("pip in /.", "bundler in /.") on
            58d431e — both failure. Not yet investigated; may or may not be
            the same permissions root cause (worth a quick check next).

          Related

          Follow-up from #102.

          Metadata

          Metadata

          Assignees

          No one assigned

            Labels

            No labels
            No labels

            Type

            No type

            Projects

            No projects

              Milestone

              No milestone

              Relationships

              None yet

              Development

              No branches or pull requests

              Issue actions

              , 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running · Issue #106 · rubykatzen/flightdeck · GitHub
              Skip to content

              Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running #106

              Description

              @ineedjet

              Problem

              #102 built the tooling (release automation, vaults//targets/ manifests,
              ansible/deploy.yml) to deploy Rybbit for rubykatzen.com on hawkeye
              through flightdeck's own pipeline, but it never got to a live deploy — the
              PR's own Verification checklist left these unchecked:

              • Publish the first real Hawkeye env asset after external prerequisites
                are configured
              • Run the first real Hawkeye deployment

              Nothing has run against production yet, and the prerequisites listed in
              #102's PR description haven't been confirmed as actually configured.

              Prerequisites to configure (from #102's PR description)

              • GitHub Secret DEPLOY_SSH_PRIVATE_KEY
              • GitHub Secret HAWKEYE_AGE_PRIVATE_KEYnew prerequisite, added
                when decryption and config rendering moved from hawkeye itself to the
                CI runner (Consider decrypting vaults on the CI runner instead of server-side #116, done alongside Consider migrating ansible/deploy.yml to Fabric (Python) #111/One vault per app: drop the APPS_/{app}_ prefix convention for vault-sourced env #114). Content is the private
                key matching keys/hawkeye.pub (previously only ever needed
                server-side, in ~/.config/sops/age/keys.txt; now needed here
                instead, not there).
              • GitHub Variable TAILSCALE_OAUTH_CLIENT_ID and Secret
                TAILSCALE_OAUTH_SECRET (if Tailscale is used to reach hawkeye)
              • Every GitHub Secret/Variable referenced by vaults/hawkeye-traefik.yml's
                and vaults/hawkeye-rybbit.yml's env: mappings: RUBYKATZEN_COM_DOMAIN,
                RUBYKATZEN_COM_ADMIN_MAIL, RUBYKATZEN_COM_CERT_RESOLVER,
                RUBYKATZEN_COM_CLOUDFLARE_TOKEN, RUBYKATZEN_COM_DATABASE_PASSWORD,
                RUBYKATZEN_COM_KEY_HEX_32, RUBYKATZEN_COM_TRAEFIK_HTTP_PORT,
                RUBYKATZEN_COM_TRAEFIK_HTTPS_PORT
              • Server-side rubykatzen-com user on hawkeye, with SSH access matching
                DEPLOY_SSH_PRIVATE_KEY. No longer needed on the server: the age
                private key, sops, gh — all moved to the CI runner side (Consider decrypting vaults on the CI runner instead of server-side #116).
                Docker and Docker Compose are the only remaining host dependencies.
              • External Cloudflare Tunnel configuration for rubykatzen.com
              • Separate open question, not blocking: apps/traefik/docker-compose.yml
                carries the Watchtower label, but hawkeye's apps doesn't include a
                watchtower app — as implemented, the automated deploy path would
                never actually run docker compose up for traefik. Needs its own
                decision (add watchtower to hawkeye's apps, or drop the label)
                before the first real deploy.

              Once prerequisites are in place

              • Publish the first real hawkeye.sops.env asset (via a real release,
                or by manually running the encrypt-vaults/encrypt jobs)
              • Run the first real deployment to hawkeye (deploy.yml
                workflow_dispatch, or let it ride the next real release)
              • Confirm traefik + rybbit actually come up and rubykatzen.com
                resolves correctly end to end

              Separately: triage currently failing/blocked workflow runs on main

              Found while checking the post-merge state of #102.

              • Releaseaction_required, zero jobs ran, on every push to main
                through 1f6117d. Root cause confirmed: repo Settings → Actions →
                General → Workflow permissions was set to "Read repository contents
                and packages permissions" — a hard cap that release.yml's own
                explicit permissions: contents: write / issues: write / pull-requests: write block could not exceed (proven by the fact it
                stayed blocked despite already declaring those permissions itself).
                Fixed by switching to "Read and write permissions" + "Allow GitHub
                Actions to create and approve pull requests" (needed separately for
                release-please's own release PR creation). Confirmed via API
                (default_workflow_permissions: "write",
                can_approve_pull_request_reviews: true). Couldn't force a live
                re-run (gh run rerun refuses runs that never started any jobs, and
                release.yml has no workflow_dispatch) — will get a real
                confirmation on the next push to main / next release-please cycle.
              • Notify Telegram PRstartup_failure on every single run
                (push, PR, and daily schedule) back through history. Same root
                cause: the GitHub error banner named it exactly — nested job
                notify requesting pull-requests: read while the repo only
                allowed pull-requests: none. Fixed by the same Settings change.
                Confirmed live via manual workflow_dispatch after the fix —
                run succeeded.
              • Dependabot update-check runs ("pip in /.", "bundler in /.") on
                58d431e — both failure. Not yet investigated; may or may not be
                the same permissions root cause (worth a quick check next).

              Related

              Follow-up from #102.

              Metadata

              Metadata

              Assignees

              No one assigned

                Labels

                No labels
                No labels

                Type

                No type

                Projects

                No projects

                  Milestone

                  No milestone

                  Relationships

                  None yet

                  Development

                  No branches or pull requests

                  Issue actions

                  , 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running · Issue #106 · rubykatzen/flightdeck · GitHub
                  Skip to content

                  Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running #106

                  Description

                  @ineedjet

                  Problem

                  #102 built the tooling (release automation, vaults//targets/ manifests,
                  ansible/deploy.yml) to deploy Rybbit for rubykatzen.com on hawkeye
                  through flightdeck's own pipeline, but it never got to a live deploy — the
                  PR's own Verification checklist left these unchecked:

                  • Publish the first real Hawkeye env asset after external prerequisites
                    are configured
                  • Run the first real Hawkeye deployment

                  Nothing has run against production yet, and the prerequisites listed in
                  #102's PR description haven't been confirmed as actually configured.

                  Prerequisites to configure (from #102's PR description)

                  • GitHub Secret DEPLOY_SSH_PRIVATE_KEY
                  • GitHub Secret HAWKEYE_AGE_PRIVATE_KEYnew prerequisite, added
                    when decryption and config rendering moved from hawkeye itself to the
                    CI runner (Consider decrypting vaults on the CI runner instead of server-side #116, done alongside Consider migrating ansible/deploy.yml to Fabric (Python) #111/One vault per app: drop the APPS_/{app}_ prefix convention for vault-sourced env #114). Content is the private
                    key matching keys/hawkeye.pub (previously only ever needed
                    server-side, in ~/.config/sops/age/keys.txt; now needed here
                    instead, not there).
                  • GitHub Variable TAILSCALE_OAUTH_CLIENT_ID and Secret
                    TAILSCALE_OAUTH_SECRET (if Tailscale is used to reach hawkeye)
                  • Every GitHub Secret/Variable referenced by vaults/hawkeye-traefik.yml's
                    and vaults/hawkeye-rybbit.yml's env: mappings: RUBYKATZEN_COM_DOMAIN,
                    RUBYKATZEN_COM_ADMIN_MAIL, RUBYKATZEN_COM_CERT_RESOLVER,
                    RUBYKATZEN_COM_CLOUDFLARE_TOKEN, RUBYKATZEN_COM_DATABASE_PASSWORD,
                    RUBYKATZEN_COM_KEY_HEX_32, RUBYKATZEN_COM_TRAEFIK_HTTP_PORT,
                    RUBYKATZEN_COM_TRAEFIK_HTTPS_PORT
                  • Server-side rubykatzen-com user on hawkeye, with SSH access matching
                    DEPLOY_SSH_PRIVATE_KEY. No longer needed on the server: the age
                    private key, sops, gh — all moved to the CI runner side (Consider decrypting vaults on the CI runner instead of server-side #116).
                    Docker and Docker Compose are the only remaining host dependencies.
                  • External Cloudflare Tunnel configuration for rubykatzen.com
                  • Separate open question, not blocking: apps/traefik/docker-compose.yml
                    carries the Watchtower label, but hawkeye's apps doesn't include a
                    watchtower app — as implemented, the automated deploy path would
                    never actually run docker compose up for traefik. Needs its own
                    decision (add watchtower to hawkeye's apps, or drop the label)
                    before the first real deploy.

                  Once prerequisites are in place

                  • Publish the first real hawkeye.sops.env asset (via a real release,
                    or by manually running the encrypt-vaults/encrypt jobs)
                  • Run the first real deployment to hawkeye (deploy.yml
                    workflow_dispatch, or let it ride the next real release)
                  • Confirm traefik + rybbit actually come up and rubykatzen.com
                    resolves correctly end to end

                  Separately: triage currently failing/blocked workflow runs on main

                  Found while checking the post-merge state of #102.

                  • Releaseaction_required, zero jobs ran, on every push to main
                    through 1f6117d. Root cause confirmed: repo Settings → Actions →
                    General → Workflow permissions was set to "Read repository contents
                    and packages permissions" — a hard cap that release.yml's own
                    explicit permissions: contents: write / issues: write / pull-requests: write block could not exceed (proven by the fact it
                    stayed blocked despite already declaring those permissions itself).
                    Fixed by switching to "Read and write permissions" + "Allow GitHub
                    Actions to create and approve pull requests" (needed separately for
                    release-please's own release PR creation). Confirmed via API
                    (default_workflow_permissions: "write",
                    can_approve_pull_request_reviews: true). Couldn't force a live
                    re-run (gh run rerun refuses runs that never started any jobs, and
                    release.yml has no workflow_dispatch) — will get a real
                    confirmation on the next push to main / next release-please cycle.
                  • Notify Telegram PRstartup_failure on every single run
                    (push, PR, and daily schedule) back through history. Same root
                    cause: the GitHub error banner named it exactly — nested job
                    notify requesting pull-requests: read while the repo only
                    allowed pull-requests: none. Fixed by the same Settings change.
                    Confirmed live via manual workflow_dispatch after the fix —
                    run succeeded.
                  • Dependabot update-check runs ("pip in /.", "bundler in /.") on
                    58d431e — both failure. Not yet investigated; may or may not be
                    the same permissions root cause (worth a quick check next).

                  Related

                  Follow-up from #102.

                  Metadata

                  Metadata

                  Assignees

                  No one assigned

                    Labels

                    No labels
                    No labels

                    Type

                    No type

                    Projects

                    No projects

                      Milestone

                      No milestone

                      Relationships

                      None yet

                      Development

                      No branches or pull requests

                      Issue actions

                      , 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running · Issue #106 · rubykatzen/flightdeck · GitHub
                      Skip to content

                      Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running #106

                      Description

                      @ineedjet

                      Problem

                      #102 built the tooling (release automation, vaults//targets/ manifests,
                      ansible/deploy.yml) to deploy Rybbit for rubykatzen.com on hawkeye
                      through flightdeck's own pipeline, but it never got to a live deploy — the
                      PR's own Verification checklist left these unchecked:

                      • Publish the first real Hawkeye env asset after external prerequisites
                        are configured
                      • Run the first real Hawkeye deployment

                      Nothing has run against production yet, and the prerequisites listed in
                      #102's PR description haven't been confirmed as actually configured.

                      Prerequisites to configure (from #102's PR description)

                      • GitHub Secret DEPLOY_SSH_PRIVATE_KEY
                      • GitHub Secret HAWKEYE_AGE_PRIVATE_KEYnew prerequisite, added
                        when decryption and config rendering moved from hawkeye itself to the
                        CI runner (Consider decrypting vaults on the CI runner instead of server-side #116, done alongside Consider migrating ansible/deploy.yml to Fabric (Python) #111/One vault per app: drop the APPS_/{app}_ prefix convention for vault-sourced env #114). Content is the private
                        key matching keys/hawkeye.pub (previously only ever needed
                        server-side, in ~/.config/sops/age/keys.txt; now needed here
                        instead, not there).
                      • GitHub Variable TAILSCALE_OAUTH_CLIENT_ID and Secret
                        TAILSCALE_OAUTH_SECRET (if Tailscale is used to reach hawkeye)
                      • Every GitHub Secret/Variable referenced by vaults/hawkeye-traefik.yml's
                        and vaults/hawkeye-rybbit.yml's env: mappings: RUBYKATZEN_COM_DOMAIN,
                        RUBYKATZEN_COM_ADMIN_MAIL, RUBYKATZEN_COM_CERT_RESOLVER,
                        RUBYKATZEN_COM_CLOUDFLARE_TOKEN, RUBYKATZEN_COM_DATABASE_PASSWORD,
                        RUBYKATZEN_COM_KEY_HEX_32, RUBYKATZEN_COM_TRAEFIK_HTTP_PORT,
                        RUBYKATZEN_COM_TRAEFIK_HTTPS_PORT
                      • Server-side rubykatzen-com user on hawkeye, with SSH access matching
                        DEPLOY_SSH_PRIVATE_KEY. No longer needed on the server: the age
                        private key, sops, gh — all moved to the CI runner side (Consider decrypting vaults on the CI runner instead of server-side #116).
                        Docker and Docker Compose are the only remaining host dependencies.
                      • External Cloudflare Tunnel configuration for rubykatzen.com
                      • Separate open question, not blocking: apps/traefik/docker-compose.yml
                        carries the Watchtower label, but hawkeye's apps doesn't include a
                        watchtower app — as implemented, the automated deploy path would
                        never actually run docker compose up for traefik. Needs its own
                        decision (add watchtower to hawkeye's apps, or drop the label)
                        before the first real deploy.

                      Once prerequisites are in place

                      • Publish the first real hawkeye.sops.env asset (via a real release,
                        or by manually running the encrypt-vaults/encrypt jobs)
                      • Run the first real deployment to hawkeye (deploy.yml
                        workflow_dispatch, or let it ride the next real release)
                      • Confirm traefik + rybbit actually come up and rubykatzen.com
                        resolves correctly end to end

                      Separately: triage currently failing/blocked workflow runs on main

                      Found while checking the post-merge state of #102.

                      • Releaseaction_required, zero jobs ran, on every push to main
                        through 1f6117d. Root cause confirmed: repo Settings → Actions →
                        General → Workflow permissions was set to "Read repository contents
                        and packages permissions" — a hard cap that release.yml's own
                        explicit permissions: contents: write / issues: write / pull-requests: write block could not exceed (proven by the fact it
                        stayed blocked despite already declaring those permissions itself).
                        Fixed by switching to "Read and write permissions" + "Allow GitHub
                        Actions to create and approve pull requests" (needed separately for
                        release-please's own release PR creation). Confirmed via API
                        (default_workflow_permissions: "write",
                        can_approve_pull_request_reviews: true). Couldn't force a live
                        re-run (gh run rerun refuses runs that never started any jobs, and
                        release.yml has no workflow_dispatch) — will get a real
                        confirmation on the next push to main / next release-please cycle.
                      • Notify Telegram PRstartup_failure on every single run
                        (push, PR, and daily schedule) back through history. Same root
                        cause: the GitHub error banner named it exactly — nested job
                        notify requesting pull-requests: read while the repo only
                        allowed pull-requests: none. Fixed by the same Settings change.
                        Confirmed live via manual workflow_dispatch after the fix —
                        run succeeded.
                      • Dependabot update-check runs ("pip in /.", "bundler in /.") on
                        58d431e — both failure. Not yet investigated; may or may not be
                        the same permissions root cause (worth a quick check next).

                      Related

                      Follow-up from #102.

                      Metadata

                      Metadata

                      Assignees

                      No one assigned

                        Labels

                        No labels
                        No labels

                        Type

                        No type

                        Projects

                        No projects

                          Milestone

                          No milestone

                          Relationships

                          None yet

                          Development

                          No branches or pull requests

                          Issue actions

                          , 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running · Issue #106 · rubykatzen/flightdeck · GitHub
                          Skip to content

                          Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running #106

                          Description

                          @ineedjet

                          Problem

                          #102 built the tooling (release automation, vaults//targets/ manifests,
                          ansible/deploy.yml) to deploy Rybbit for rubykatzen.com on hawkeye
                          through flightdeck's own pipeline, but it never got to a live deploy — the
                          PR's own Verification checklist left these unchecked:

                          • Publish the first real Hawkeye env asset after external prerequisites
                            are configured
                          • Run the first real Hawkeye deployment

                          Nothing has run against production yet, and the prerequisites listed in
                          #102's PR description haven't been confirmed as actually configured.

                          Prerequisites to configure (from #102's PR description)

                          • GitHub Secret DEPLOY_SSH_PRIVATE_KEY
                          • GitHub Secret HAWKEYE_AGE_PRIVATE_KEYnew prerequisite, added
                            when decryption and config rendering moved from hawkeye itself to the
                            CI runner (Consider decrypting vaults on the CI runner instead of server-side #116, done alongside Consider migrating ansible/deploy.yml to Fabric (Python) #111/One vault per app: drop the APPS_/{app}_ prefix convention for vault-sourced env #114). Content is the private
                            key matching keys/hawkeye.pub (previously only ever needed
                            server-side, in ~/.config/sops/age/keys.txt; now needed here
                            instead, not there).
                          • GitHub Variable TAILSCALE_OAUTH_CLIENT_ID and Secret
                            TAILSCALE_OAUTH_SECRET (if Tailscale is used to reach hawkeye)
                          • Every GitHub Secret/Variable referenced by vaults/hawkeye-traefik.yml's
                            and vaults/hawkeye-rybbit.yml's env: mappings: RUBYKATZEN_COM_DOMAIN,
                            RUBYKATZEN_COM_ADMIN_MAIL, RUBYKATZEN_COM_CERT_RESOLVER,
                            RUBYKATZEN_COM_CLOUDFLARE_TOKEN, RUBYKATZEN_COM_DATABASE_PASSWORD,
                            RUBYKATZEN_COM_KEY_HEX_32, RUBYKATZEN_COM_TRAEFIK_HTTP_PORT,
                            RUBYKATZEN_COM_TRAEFIK_HTTPS_PORT
                          • Server-side rubykatzen-com user on hawkeye, with SSH access matching
                            DEPLOY_SSH_PRIVATE_KEY. No longer needed on the server: the age
                            private key, sops, gh — all moved to the CI runner side (Consider decrypting vaults on the CI runner instead of server-side #116).
                            Docker and Docker Compose are the only remaining host dependencies.
                          • External Cloudflare Tunnel configuration for rubykatzen.com
                          • Separate open question, not blocking: apps/traefik/docker-compose.yml
                            carries the Watchtower label, but hawkeye's apps doesn't include a
                            watchtower app — as implemented, the automated deploy path would
                            never actually run docker compose up for traefik. Needs its own
                            decision (add watchtower to hawkeye's apps, or drop the label)
                            before the first real deploy.

                          Once prerequisites are in place

                          • Publish the first real hawkeye.sops.env asset (via a real release,
                            or by manually running the encrypt-vaults/encrypt jobs)
                          • Run the first real deployment to hawkeye (deploy.yml
                            workflow_dispatch, or let it ride the next real release)
                          • Confirm traefik + rybbit actually come up and rubykatzen.com
                            resolves correctly end to end

                          Separately: triage currently failing/blocked workflow runs on main

                          Found while checking the post-merge state of #102.

                          • Releaseaction_required, zero jobs ran, on every push to main
                            through 1f6117d. Root cause confirmed: repo Settings → Actions →
                            General → Workflow permissions was set to "Read repository contents
                            and packages permissions" — a hard cap that release.yml's own
                            explicit permissions: contents: write / issues: write / pull-requests: write block could not exceed (proven by the fact it
                            stayed blocked despite already declaring those permissions itself).
                            Fixed by switching to "Read and write permissions" + "Allow GitHub
                            Actions to create and approve pull requests" (needed separately for
                            release-please's own release PR creation). Confirmed via API
                            (default_workflow_permissions: "write",
                            can_approve_pull_request_reviews: true). Couldn't force a live
                            re-run (gh run rerun refuses runs that never started any jobs, and
                            release.yml has no workflow_dispatch) — will get a real
                            confirmation on the next push to main / next release-please cycle.
                          • Notify Telegram PRstartup_failure on every single run
                            (push, PR, and daily schedule) back through history. Same root
                            cause: the GitHub error banner named it exactly — nested job
                            notify requesting pull-requests: read while the repo only
                            allowed pull-requests: none. Fixed by the same Settings change.
                            Confirmed live via manual workflow_dispatch after the fix —
                            run succeeded.
                          • Dependabot update-check runs ("pip in /.", "bundler in /.") on
                            58d431e — both failure. Not yet investigated; may or may not be
                            the same permissions root cause (worth a quick check next).

                          Related

                          Follow-up from #102.

                          Metadata

                          Metadata

                          Assignees

                          No one assigned

                            Labels

                            No labels
                            No labels

                            Type

                            No type

                            Projects

                            No projects

                              Milestone

                              No milestone

                              Relationships

                              None yet

                              Development

                              No branches or pull requests

                              Issue actions

                              , 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running · Issue #106 · rubykatzen/flightdeck · GitHub
                              Skip to content

                              Normalize the hawkeye/rybbit deploy: configure prerequisites and get the first real deployment running #106

                              Description

                              @ineedjet

                              Problem

                              #102 built the tooling (release automation, vaults//targets/ manifests,
                              ansible/deploy.yml) to deploy Rybbit for rubykatzen.com on hawkeye
                              through flightdeck's own pipeline, but it never got to a live deploy — the
                              PR's own Verification checklist left these unchecked:

                              • Publish the first real Hawkeye env asset after external prerequisites
                                are configured
                              • Run the first real Hawkeye deployment

                              Nothing has run against production yet, and the prerequisites listed in
                              #102's PR description haven't been confirmed as actually configured.

                              Prerequisites to configure (from #102's PR description)

                              • GitHub Secret DEPLOY_SSH_PRIVATE_KEY
                              • GitHub Secret HAWKEYE_AGE_PRIVATE_KEYnew prerequisite, added
                                when decryption and config rendering moved from hawkeye itself to the
                                CI runner (Consider decrypting vaults on the CI runner instead of server-side #116, done alongside Consider migrating ansible/deploy.yml to Fabric (Python) #111/One vault per app: drop the APPS_/{app}_ prefix convention for vault-sourced env #114). Content is the private
                                key matching keys/hawkeye.pub (previously only ever needed
                                server-side, in ~/.config/sops/age/keys.txt; now needed here
                                instead, not there).
                              • GitHub Variable TAILSCALE_OAUTH_CLIENT_ID and Secret
                                TAILSCALE_OAUTH_SECRET (if Tailscale is used to reach hawkeye)
                              • Every GitHub Secret/Variable referenced by vaults/hawkeye-traefik.yml's
                                and vaults/hawkeye-rybbit.yml's env: mappings: RUBYKATZEN_COM_DOMAIN,
                                RUBYKATZEN_COM_ADMIN_MAIL, RUBYKATZEN_COM_CERT_RESOLVER,
                                RUBYKATZEN_COM_CLOUDFLARE_TOKEN, RUBYKATZEN_COM_DATABASE_PASSWORD,
                                RUBYKATZEN_COM_KEY_HEX_32, RUBYKATZEN_COM_TRAEFIK_HTTP_PORT,
                                RUBYKATZEN_COM_TRAEFIK_HTTPS_PORT
                              • Server-side rubykatzen-com user on hawkeye, with SSH access matching
                                DEPLOY_SSH_PRIVATE_KEY. No longer needed on the server: the age
                                private key, sops, gh — all moved to the CI runner side (Consider decrypting vaults on the CI runner instead of server-side #116).
                                Docker and Docker Compose are the only remaining host dependencies.
                              • External Cloudflare Tunnel configuration for rubykatzen.com
                              • Separate open question, not blocking: apps/traefik/docker-compose.yml
                                carries the Watchtower label, but hawkeye's apps doesn't include a
                                watchtower app — as implemented, the automated deploy path would
                                never actually run docker compose up for traefik. Needs its own
                                decision (add watchtower to hawkeye's apps, or drop the label)
                                before the first real deploy.

                              Once prerequisites are in place

                              • Publish the first real hawkeye.sops.env asset (via a real release,
                                or by manually running the encrypt-vaults/encrypt jobs)
                              • Run the first real deployment to hawkeye (deploy.yml
                                workflow_dispatch, or let it ride the next real release)
                              • Confirm traefik + rybbit actually come up and rubykatzen.com
                                resolves correctly end to end

                              Separately: triage currently failing/blocked workflow runs on main

                              Found while checking the post-merge state of #102.

                              • Releaseaction_required, zero jobs ran, on every push to main
                                through 1f6117d. Root cause confirmed: repo Settings → Actions →
                                General → Workflow permissions was set to "Read repository contents
                                and packages permissions" — a hard cap that release.yml's own
                                explicit permissions: contents: write / issues: write / pull-requests: write block could not exceed (proven by the fact it
                                stayed blocked despite already declaring those permissions itself).
                                Fixed by switching to "Read and write permissions" + "Allow GitHub
                                Actions to create and approve pull requests" (needed separately for
                                release-please's own release PR creation). Confirmed via API
                                (default_workflow_permissions: "write",
                                can_approve_pull_request_reviews: true). Couldn't force a live
                                re-run (gh run rerun refuses runs that never started any jobs, and
                                release.yml has no workflow_dispatch) — will get a real
                                confirmation on the next push to main / next release-please cycle.
                              • Notify Telegram PRstartup_failure on every single run
                                (push, PR, and daily schedule) back through history. Same root
                                cause: the GitHub error banner named it exactly — nested job
                                notify requesting pull-requests: read while the repo only
                                allowed pull-requests: none. Fixed by the same Settings change.
                                Confirmed live via manual workflow_dispatch after the fix —
                                run succeeded.
                              • Dependabot update-check runs ("pip in /.", "bundler in /.") on
                                58d431e — both failure. Not yet investigated; may or may not be
                                the same permissions root cause (worth a quick check next).

                              Related

                              Follow-up from #102.

                              Metadata

                              Metadata

                              Assignees

                              No one assigned

                                Labels

                                No labels
                                No labels

                                Type

                                No type

                                Projects

                                No projects

                                  Milestone

                                  No milestone

                                  Relationships

                                  None yet

                                  Development

                                  No branches or pull requests

                                  Issue actions