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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 25 additions & 21 deletions .github/workflows/RDP + Tailscale (STOP & RESTART).yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ name: RDP + Tailscale (STOP & RESTART)
on:
workflow_dispatch:
inputs:
ts_tailnet: { description: "Tailscale tailnet", required: true }
ts_api_key: { description: "Tailscale API key", required: true }
ts_authkey: { description: "Tailscale Auth key", required: true }
quick_test: { description: "Restart with 5-min test", type: boolean, default: false }
runtime_minutes: { description: "Runtime for restart", required: false, default: "355" }
do_purge: { description: "Purge bullet devices", required: false, default: "true" }
Expand All @@ -25,10 +22,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Purge bullet* devices
env:
TS_API_KEY: ${{ secrets.TS_API_KEY }}
TS_TAILNET: ${{ secrets.TS_TAILNET }}
run: |
try{
$auth=[Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${{ inputs.ts_api_key }}:"))
$tn=[uri]::EscapeDataString("${{ inputs.ts_tailnet }}")
$auth=[Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("$($env:TS_API_KEY):"))
$tn=[uri]::EscapeDataString($env:TS_TAILNET)
$list=Invoke-RestMethod "https://api.tailscale.com/api/v2/tailnet/$tn/devices" -Headers @{Authorization="Basic $auth"}
$count=0
foreach($d in $list.devices){
Expand All @@ -37,46 +37,50 @@ jobs:
$count++
}
}
Write-Host "🧹 Removed $count bullet devices from Tailscale."
}catch{Write-Host "⚠️ Cleanup failed: $($_.Exception.Message)"}
Write-Host "Removed $count bullet devices from Tailscale."
}catch{Write-Host "Cleanup failed: $($_.Exception.Message)"}

- name: Decide next step
id: next
env:
INPUT_CYCLES_LEFT: ${{ inputs.cycles_left }}
run: |
$left=[int]"${{ inputs.cycles_left }}"
$left=[int]$env:INPUT_CYCLES_LEFT
if($left -le 0){
Write-Host "✅ 5 cycles completed. Stopping permanently."
Write-Host "All cycles completed. Stopping permanently."
"RESTART=0"|Out-File -Append $env:GITHUB_ENV
}else{
Write-Host "Waiting 20 min before restarting Workflow 1. Cycles left: $left"
Write-Host "Waiting 20 min before restarting Workflow 1. Cycles left: $left"
"RESTART=1"|Out-File -Append $env:GITHUB_ENV
}

- name: Wait 20 minutes (if restarting)
if: env.RESTART == '1'
run: |
$end=(Get-Date).AddMinutes(20)
while((Get-Date) -lt $end){Write-Host ("🕒 Cooling down "+(Get-Date));Start-Sleep 60}
while((Get-Date) -lt $end){Write-Host ("Cooling down "+(Get-Date));Start-Sleep 60}

- name: Restart Workflow 1 (if cycles remain)
if: env.RESTART == '1'
env:
GH_TOKEN: ${{ github.token }}
INPUT_CYCLES_LEFT: ${{ inputs.cycles_left }}
INPUT_QUICK_TEST: ${{ inputs.quick_test }}
INPUT_RUNTIME_MINUTES: ${{ inputs.runtime_minutes }}
INPUT_DO_PURGE: ${{ inputs.do_purge }}
INPUT_RDP_COUNT: ${{ inputs.rdp_count }}
run: |
$next=[int]"${{ inputs.cycles_left }}"-1
if($next -le 0){Write-Host "Finished all cycles.";exit 0}
$next=[int]$env:INPUT_CYCLES_LEFT-1
if($next -le 0){Write-Host "Finished all cycles.";exit 0}
$payload=@{
ts_tailnet="${{ inputs.ts_tailnet }}"
ts_api_key="${{ inputs.ts_api_key }}"
ts_authkey="${{ inputs.ts_authkey }}"
quick_test="${{ inputs.quick_test }}"
runtime_minutes="${{ inputs.runtime_minutes }}"
do_purge="${{ inputs.do_purge }}"
rdp_count="${{ inputs.rdp_count }}"
quick_test=$env:INPUT_QUICK_TEST
runtime_minutes=$env:INPUT_RUNTIME_MINUTES
do_purge=$env:INPUT_DO_PURGE
rdp_count=$env:INPUT_RDP_COUNT
cycles_left="$next"
}
$url="https://api.github.com/repos/${{ github.repository }}/actions/workflows/workflow-1.yml/dispatches"
$hdr=@{Authorization="Bearer $env:GH_TOKEN";Accept="application/vnd.github+json"}
$body=@{ref="${{ github.ref_name }}";inputs=$payload}|ConvertTo-Json -Depth 20
Invoke-WebRequest -Method POST -Uri $url -Headers $hdr -Body $body|Out-Null
Write-Host "🚀 Workflow 1 restarted (cycles left: $next)"
Write-Host "Workflow 1 restarted (cycles left: $next)"
43 changes: 24 additions & 19 deletions .github/workflows/RDP + Tailscale (Workflow 1).yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ name: RDP + Tailscale (Workflow 1)
on:
workflow_dispatch:
inputs:
ts_tailnet: { description: "Tailscale tailnet (e.g. you@gmail.com)", required: true }
ts_api_key: { description: "Tailscale API key (device admin, no Bearer)", required: true }
ts_authkey: { description: "Tailscale Auth key", required: true }
quick_test: { description: "Run 5-minute test", type: boolean, default: false }
runtime_minutes: { description: "Runtime minutes", required: false, default: "355" }
do_purge: { description: "Purge bullet* devices", required: false, default: "true" }
Expand All @@ -27,8 +24,10 @@ jobs:
matrix: ${{ steps.mk.outputs.matrix }}
steps:
- id: mk
env:
INPUT_RDP_COUNT: ${{ inputs.rdp_count }}
run: |
$n=[int]"${{ inputs.rdp_count }}"
$n=[int]$env:INPUT_RDP_COUNT
if($n -lt 1){$n=1}; if($n -gt 10){$n=10}
$arr=@(); for($i=1;$i -le $n;$i++){ $arr+=@{id=$i} }
$json=@{include=$arr}|ConvertTo-Json -Compress
Expand All @@ -41,19 +40,24 @@ jobs:
matrix: ${{ fromJson(needs.setup.outputs.matrix) }}
timeout-minutes: 370
env:
RDP_USER: Bullettemporary
RDP_PASS: Bullet@12345
RDP_USER: ${{ secrets.RDP_USER }}
RDP_PASS: ${{ secrets.RDP_PASS }}

steps:
- name: Decide runtime
env:
INPUT_QUICK_TEST: ${{ inputs.quick_test }}
INPUT_RUNTIME_MINUTES: ${{ inputs.runtime_minutes }}
run: |
function Yes($v){ "$v" -match '^(?i:true|1|yes|on)$' }
$rt=if(Yes("${{ inputs.quick_test }}")){5}else{[int]"${{ inputs.runtime_minutes }}"}
$rt=if(Yes($env:INPUT_QUICK_TEST)){5}else{[int]$env:INPUT_RUNTIME_MINUTES}
if($rt -gt 360){$rt=355}
"RUNTIME_MINUTES=$rt"|Out-File -Append $env:GITHUB_ENV
Write-Host "Runtime set to $rt minutes"

- name: Install + Configure Tailscale
env:
TS_AUTHKEY: ${{ secrets.TS_AUTHKEY }}
run: |
$ts="$env:ProgramFiles\Tailscale\tailscale.exe"
if(-not(Test-Path $ts)){
Expand All @@ -62,7 +66,7 @@ jobs:
Invoke-WebRequest $url -OutFile $dst
Start-Process msiexec.exe -ArgumentList "/i","`"$dst`"","/quiet","/norestart" -Wait
}
& $ts up --authkey "${{ inputs.ts_authkey }}" --hostname "bullet1" --accept-dns=true
& $ts up --authkey $env:TS_AUTHKEY --hostname "bullet1" --accept-dns=true
$ip=& $ts ip -4 |Select-Object -First 1
"TAILSCALE_IP=$ip"|Out-File -Append $env:GITHUB_ENV
Write-Host "Tailscale IPv4: $ip"
Expand All @@ -73,12 +77,11 @@ jobs:
$s=ConvertTo-SecureString $p -AsPlainText -Force
if(-not(Get-LocalUser -Name $u -EA SilentlyContinue)){
New-LocalUser -Name $u -Password $s -AccountNeverExpires
Add-LocalGroupMember -Group "Administrators" -Member $u
Add-LocalGroupMember -Group "Remote Desktop Users" -Member $u
}
Set-ItemProperty "HKLM:\System\CurrentControlSet\Control\Terminal Server" fDenyTSConnections 0
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"
Write-Host "RDP ready: $u / $p @ $env:TAILSCALE_IP"
Write-Host "RDP ready for user $u @ $env:TAILSCALE_IP"

- name: Install Python libs
run: |
Expand All @@ -94,20 +97,22 @@ jobs:
if: always()
env:
GH_TOKEN: ${{ github.token }}
INPUT_CYCLES_LEFT: ${{ inputs.cycles_left }}
INPUT_QUICK_TEST: ${{ inputs.quick_test }}
INPUT_RUNTIME_MINUTES: ${{ inputs.runtime_minutes }}
INPUT_DO_PURGE: ${{ inputs.do_purge }}
INPUT_RDP_COUNT: ${{ inputs.rdp_count }}
run: |
$next=[int]"${{ inputs.cycles_left }}"-1
$next=[int]$env:INPUT_CYCLES_LEFT-1
$payload=@{
ts_tailnet="${{ inputs.ts_tailnet }}"
ts_api_key="${{ inputs.ts_api_key }}"
ts_authkey="${{ inputs.ts_authkey }}"
quick_test="${{ inputs.quick_test }}"
runtime_minutes="${{ inputs.runtime_minutes }}"
do_purge="${{ inputs.do_purge }}"
rdp_count="${{ inputs.rdp_count }}"
quick_test=$env:INPUT_QUICK_TEST
runtime_minutes=$env:INPUT_RUNTIME_MINUTES
do_purge=$env:INPUT_DO_PURGE
rdp_count=$env:INPUT_RDP_COUNT
cycles_left="$next"
}
$url="https://api.github.com/repos/${{ github.repository }}/actions/workflows/workflow-2.yml/dispatches"
$hdr=@{Authorization="Bearer $env:GH_TOKEN";Accept="application/vnd.github+json"}
$body=@{ref="${{ github.ref_name }}";inputs=$payload}|ConvertTo-Json -Depth 20
Invoke-WebRequest -Method POST -Uri $url -Headers $hdr -Body $body|Out-Null
Write-Host "➡️ Workflow 2 triggered. Cycles left: $next"
Write-Host "Workflow 2 triggered. Cycles left: $next"
35 changes: 19 additions & 16 deletions .github/workflows/RDP + Tailscale (Workflow 2).yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ name: RDP + Tailscale (Workflow 2)
on:
workflow_dispatch:
inputs:
ts_tailnet: { description: "Tailscale tailnet", required: true }
ts_api_key: { description: "Tailscale API key", required: true }
ts_authkey: { description: "Tailscale Auth key", required: true }
quick_test: { description: "Run 5-min test", type: boolean, default: false }
runtime_minutes: { description: "Runtime", required: false, default: "355" }
do_purge: { description: "Purge bullet devices", required: false, default: "true" }
Expand All @@ -25,11 +22,13 @@ jobs:
runs-on: windows-latest
timeout-minutes: 370
env:
RDP_USER: Bullettemporary
RDP_PASS: Bullet@12345
RDP_USER: ${{ secrets.RDP_USER }}
RDP_PASS: ${{ secrets.RDP_PASS }}

steps:
- name: Setup Tailscale + RDP
env:
TS_AUTHKEY: ${{ secrets.TS_AUTHKEY }}
run: |
$ts="$env:ProgramFiles\Tailscale\tailscale.exe"
if(-not(Test-Path $ts)){
Expand All @@ -38,7 +37,7 @@ jobs:
Invoke-WebRequest $url -OutFile $dst
Start-Process msiexec.exe -ArgumentList "/i","`"$dst`"","/quiet","/norestart" -Wait
}
& $ts up --authkey "${{ inputs.ts_authkey }}" --hostname "bullet2" --accept-dns=true
& $ts up --authkey $env:TS_AUTHKEY --hostname "bullet2" --accept-dns=true
Enable-NetFirewallRule -DisplayGroup "Remote Desktop"

- name: Install Python libs
Expand All @@ -47,28 +46,32 @@ jobs:
python -m pip install --force-reinstall pyautogui pynput pillow

- name: Keep alive
env:
INPUT_RUNTIME_MINUTES: ${{ inputs.runtime_minutes }}
run: |
$rt=[int]"${{ inputs.runtime_minutes }}"
$rt=[int]$env:INPUT_RUNTIME_MINUTES
$end=(Get-Date).AddMinutes($rt)
while((Get-Date) -lt $end){Write-Host ("Workflow2 heartbeat "+(Get-Date));Start-Sleep 60}

- name: Dispatch STOP workflow
if: always()
env:
GH_TOKEN: ${{ github.token }}
INPUT_QUICK_TEST: ${{ inputs.quick_test }}
INPUT_RUNTIME_MINUTES: ${{ inputs.runtime_minutes }}
INPUT_DO_PURGE: ${{ inputs.do_purge }}
INPUT_RDP_COUNT: ${{ inputs.rdp_count }}
INPUT_CYCLES_LEFT: ${{ inputs.cycles_left }}
run: |
$payload=@{
ts_tailnet="${{ inputs.ts_tailnet }}"
ts_api_key="${{ inputs.ts_api_key }}"
ts_authkey="${{ inputs.ts_authkey }}"
quick_test="${{ inputs.quick_test }}"
runtime_minutes="${{ inputs.runtime_minutes }}"
do_purge="${{ inputs.do_purge }}"
rdp_count="${{ inputs.rdp_count }}"
cycles_left="${{ inputs.cycles_left }}"
quick_test=$env:INPUT_QUICK_TEST
runtime_minutes=$env:INPUT_RUNTIME_MINUTES
do_purge=$env:INPUT_DO_PURGE
rdp_count=$env:INPUT_RDP_COUNT
cycles_left=$env:INPUT_CYCLES_LEFT
}
$url="https://api.github.com/repos/${{ github.repository }}/actions/workflows/workflow-stop.yml/dispatches"
$hdr=@{Authorization="Bearer $env:GH_TOKEN";Accept="application/vnd.github+json"}
$body=@{ref="${{ github.ref_name }}";inputs=$payload}|ConvertTo-Json -Depth 20
Invoke-WebRequest -Method POST -Uri $url -Headers $hdr -Body $body|Out-Null
Write-Host "🛑 STOP workflow triggered (cycles left: ${{ inputs.cycles_left }})"
Write-Host "STOP workflow triggered (cycles left: $env:INPUT_CYCLES_LEFT)"