https://github.com/omercnet/doh1
https://github.com/omercnet/doh1
Last synced: 5 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/omercnet/doh1
- Owner: omercnet
- Created: 2025-12-28T08:15:02.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-12-28T09:07:37.000Z (6 months ago)
- Last Synced: 2025-12-30T16:42:36.628Z (6 months ago)
- Language: TypeScript
- Size: 46.9 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Agents: AGENTS.md
Awesome Lists containing this project
README
# 🪖 דו"ח 1 - IDF Daily Attendance Automation
Automated daily attendance form submission for IDF reservists using Playwright.
> **📋 This is a template repo!** Click [**Use this template**](https://github.com/omercnet/doh1/generate) to create your own.
```
┌─────────────────────────────────────────────────────────────┐
│ 🇮🇱 🇮🇱 │
│ ╔═══╗ ╔═══╗ ╔═╗ ╔═╗ ╔═══╗ │
│ ║ ║ ║ ║ ║ ║ ║ ║ ║ │
│ ║ ║ ║ ║ ║ ╚═╝ ║ ║ │
│ ║ ║ ║ ║ ║ ╔═╗ ║ ║ │
│ ╚═══╝ ╚═══╝ ╚═╝ ╚═╝ ║ │
│ │
│ ⭐ Automate your מעקב נוכחות יומי ⭐ │
│ │
└─────────────────────────────────────────────────────────────┘
```
## What it does
- 🔐 Logs into miluim.idf.il with Azure AD authentication
- 📞 Handles MFA via phone call (you approve, it continues)
- 📝 Submits daily attendance form (דו"ח 1)
- ✅ Detects if already submitted today and skips gracefully
- 💾 Caches auth session to skip MFA on subsequent runs
- ⏰ Runs on schedule via GitHub Actions
- 📢 Notifies via Slack on success/failure
## 🛠️ Local Development
### Prerequisites
- [mise](https://mise.jdx.dev/) - Runtime version manager
- [fnox](https://github.com/jdx/fnox) - Secret management
### Setup
1. **Install dependencies:**
```bash
mise install
pnpm install
npx playwright install chromium
```
2. **Configure secrets:**
```bash
# Generate an age key if you don't have one
age-keygen -o ~/.config/fnox/age.txt
# Copy the PUBLIC key (starts with age1...) for fnox.toml
cat ~/.config/fnox/age.txt | grep "public key"
# Create your fnox.toml
cp fnox.toml.example fnox.toml
# Edit fnox.toml - replace YOUR_AGE_PUBLIC_KEY with your public key
# Add your secrets
fnox set IDF_ID
fnox set IDF_PASSWORD
```
3. **Run locally (headed):**
```bash
fnox run -- pnpm test:headed
```
When MFA triggers, approve the phone call.
4. **Run headless:**
```bash
fnox run -- pnpm test
```
## 🚀 GitHub Actions Setup
### Required Secrets
| Secret | Description |
| -------------------- | ------------------------------------------------ |
| `IDF_ID` | Your ID number (ת.ז.) |
| `IDF_PASSWORD` | Your Azure AD password |
| `TS_OAUTH_CLIENT_ID` | Tailscale OAuth client ID |
| `TS_OAUTH_SECRET` | Tailscale OAuth client secret |
| `TS_EXIT_NODE` | Tailscale exit node hostname (your home machine) |
### Optional Secrets
| Secret | Description |
| ------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `AGE_RECIPIENT` | Age public key (starts with `age1...`) for encrypting failed test artifacts. Get it from `~/.config/fnox/age.txt` |
| `SLACK_WEBHOOK_URL` | Slack webhook for notifications |
### Tailscale Setup
The IDF portal blocks access from cloud IPs (Azure AD Conditional Access). CI routes traffic through your home network via Tailscale.
1. **Enable exit node on your home machine:**
```bash
sudo tailscale up --advertise-exit-node
```
Then approve it in the [Tailscale admin console](https://login.tailscale.com/admin/machines).
2. **Add ACL tag for CI nodes:**
Add to your [Tailscale ACL policy](https://login.tailscale.com/admin/acls):
```json
"tagOwners": {
"tag:ci": ["autogroup:admin"]
}
```
3. **Create OAuth client:**
- Go to [Tailscale Settings → OAuth clients](https://login.tailscale.com/admin/settings/oauth)
- Click "Generate OAuth client"
- Add `tag:ci` tag
- Scopes: `auth_keys` (writable)
- Copy the **Client ID** and **Client Secret**
4. **Add GitHub repository secrets:**
- Go to repo Settings → Secrets and variables → Actions → Secrets
- Add `TS_OAUTH_CLIENT_ID` with the client ID (without `api.tailscale.com/` prefix)
- Add `TS_OAUTH_SECRET` with the client secret
- Add `TS_EXIT_NODE` with your home machine's Tailscale hostname
> **Note:** The age private key stays local in `~/.config/fnox/age.txt`. Only the public key goes to GitHub for encrypting artifacts you can decrypt locally.
### Schedule
Runs automatically Sunday-Thursday at 9:00 AM Israel time.
To run manually: Actions → Daily Attendance Form → Run workflow
### First Run
The first CI run (or after session expires) will require MFA:
1. Trigger the workflow
2. Wait for the phone call
3. Approve MFA
4. Session gets cached for future runs
## 🔧 Troubleshooting
### Decrypting Failed Test Artifacts
If a run fails, traces are encrypted and uploaded as artifacts.
```bash
# Download the artifact, then:
age -d -i ~/.config/fnox/age.txt test-results.tar.gz.age > test-results.tar.gz
tar -xzf test-results.tar.gz
npx playwright show-trace test-results/*/trace.zip
```
### Force Re-authentication
If the cached session is stale:
1. Go to Actions → Daily Attendance Form
2. Run workflow with "Force new login" checked
### Common Issues
| Issue | Solution |
| --------------------- | ---------------------------------------------------------- |
| MFA timeout | Be ready to approve the call within 3 minutes |
| Session expired | Force re-login via workflow dispatch |
| Already submitted | This is fine! Test passes with "Already submitted today ✓" |
| Selectors changed | Update selectors in `src/form/fill-attendance.ts` |
| "Cannot access" error | Azure AD blocking cloud IPs - check Tailscale exit node |
| Tailscale timeout | Ensure home machine is online and exit node is approved |
## 📁 Project Structure
```
src/
├── config.ts # Environment config
├── auth/
│ └── login.ts # Azure AD + MFA login flow
├── form/
│ └── fill-attendance.ts # Form submission logic
└── utils/
└── notify.ts # Slack/email notifications
tests/
└── test-1.spec.ts # Main test orchestrator
.github/workflows/
└── playwright.yml # CI workflow
```
## 📜 License
ISC
---
🎖️ _Made for מילואימניקים by מילואימניקים_ 🎖️