syft-bg 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. syft_bg-0.2.0/.gitignore +178 -0
  2. syft_bg-0.2.0/PKG-INFO +276 -0
  3. syft_bg-0.2.0/README.md +258 -0
  4. syft_bg-0.2.0/pyproject.toml +32 -0
  5. syft_bg-0.2.0/src/syft_bg/__init__.py +6 -0
  6. syft_bg-0.2.0/src/syft_bg/__main__.py +6 -0
  7. syft_bg-0.2.0/src/syft_bg/api.py +116 -0
  8. syft_bg-0.2.0/src/syft_bg/approve/__init__.py +11 -0
  9. syft_bg-0.2.0/src/syft_bg/approve/config.py +118 -0
  10. syft_bg-0.2.0/src/syft_bg/approve/criteria.py +109 -0
  11. syft_bg-0.2.0/src/syft_bg/approve/handlers/__init__.py +6 -0
  12. syft_bg-0.2.0/src/syft_bg/approve/handlers/job.py +91 -0
  13. syft_bg-0.2.0/src/syft_bg/approve/handlers/peer.py +105 -0
  14. syft_bg-0.2.0/src/syft_bg/approve/monitors/__init__.py +6 -0
  15. syft_bg-0.2.0/src/syft_bg/approve/monitors/job.py +41 -0
  16. syft_bg-0.2.0/src/syft_bg/approve/monitors/peer.py +37 -0
  17. syft_bg-0.2.0/src/syft_bg/approve/orchestrator.py +169 -0
  18. syft_bg-0.2.0/src/syft_bg/cli/__init__.py +3 -0
  19. syft_bg-0.2.0/src/syft_bg/cli/commands.py +791 -0
  20. syft_bg-0.2.0/src/syft_bg/cli/init/__init__.py +5 -0
  21. syft_bg-0.2.0/src/syft_bg/cli/init/drive_setup.py +105 -0
  22. syft_bg-0.2.0/src/syft_bg/cli/init/flow.py +370 -0
  23. syft_bg-0.2.0/src/syft_bg/cli/init/gmail_setup.py +80 -0
  24. syft_bg-0.2.0/src/syft_bg/common/__init__.py +19 -0
  25. syft_bg-0.2.0/src/syft_bg/common/config.py +73 -0
  26. syft_bg-0.2.0/src/syft_bg/common/drive.py +47 -0
  27. syft_bg-0.2.0/src/syft_bg/common/monitor.py +69 -0
  28. syft_bg-0.2.0/src/syft_bg/common/orchestrator.py +108 -0
  29. syft_bg-0.2.0/src/syft_bg/common/state.py +151 -0
  30. syft_bg-0.2.0/src/syft_bg/notify/__init__.py +6 -0
  31. syft_bg-0.2.0/src/syft_bg/notify/config.py +54 -0
  32. syft_bg-0.2.0/src/syft_bg/notify/email_templates/__init__.py +5 -0
  33. syft_bg-0.2.0/src/syft_bg/notify/email_templates/renderer.py +70 -0
  34. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/base.html +252 -0
  35. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/components/button.html +48 -0
  36. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/components/info_box.html +50 -0
  37. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/emails/job_approved.html +32 -0
  38. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/emails/job_approved_do.html +25 -0
  39. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/emails/job_completed_do.html +19 -0
  40. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/emails/job_executed.html +46 -0
  41. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/emails/job_rejected_do.html +32 -0
  42. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/emails/job_rejected_ds.html +31 -0
  43. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/emails/new_job.html +41 -0
  44. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/emails/new_peer_request.html +54 -0
  45. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/emails/peer_added.html +51 -0
  46. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/emails/peer_granted.html +51 -0
  47. syft_bg-0.2.0/src/syft_bg/notify/email_templates/templates/emails/peer_request_sent.html +51 -0
  48. syft_bg-0.2.0/src/syft_bg/notify/gmail/__init__.py +6 -0
  49. syft_bg-0.2.0/src/syft_bg/notify/gmail/auth.py +63 -0
  50. syft_bg-0.2.0/src/syft_bg/notify/gmail/sender.py +418 -0
  51. syft_bg-0.2.0/src/syft_bg/notify/handlers/__init__.py +6 -0
  52. syft_bg-0.2.0/src/syft_bg/notify/handlers/job.py +178 -0
  53. syft_bg-0.2.0/src/syft_bg/notify/handlers/peer.py +103 -0
  54. syft_bg-0.2.0/src/syft_bg/notify/monitors/__init__.py +6 -0
  55. syft_bg-0.2.0/src/syft_bg/notify/monitors/job.py +219 -0
  56. syft_bg-0.2.0/src/syft_bg/notify/monitors/peer.py +147 -0
  57. syft_bg-0.2.0/src/syft_bg/notify/orchestrator.py +122 -0
  58. syft_bg-0.2.0/src/syft_bg/services/__init__.py +5 -0
  59. syft_bg-0.2.0/src/syft_bg/services/base.py +164 -0
  60. syft_bg-0.2.0/src/syft_bg/services/manager.py +66 -0
  61. syft_bg-0.2.0/src/syft_bg/services/registry.py +27 -0
  62. syft_bg-0.2.0/src/syft_bg/systemd/__init__.py +5 -0
  63. syft_bg-0.2.0/src/syft_bg/systemd/installer.py +146 -0
  64. syft_bg-0.2.0/src/syft_bg/tui/__init__.py +5 -0
  65. syft_bg-0.2.0/src/syft_bg/tui/app.py +154 -0
  66. syft_bg-0.2.0/src/syft_bg/tui/screens/__init__.py +5 -0
  67. syft_bg-0.2.0/src/syft_bg/tui/screens/log_screen.py +71 -0
  68. syft_bg-0.2.0/src/syft_bg/tui/widgets/__init__.py +6 -0
  69. syft_bg-0.2.0/src/syft_bg/tui/widgets/activity_feed.py +144 -0
  70. syft_bg-0.2.0/src/syft_bg/tui/widgets/service_card.py +169 -0
@@ -0,0 +1,178 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ credentials/
7
+
8
+ # C extensions
9
+ *.so
10
+
11
+ # Distribution / packaging
12
+ .Python
13
+ build/
14
+ develop-eggs/
15
+ dist/
16
+ downloads/
17
+ eggs/
18
+ .eggs/
19
+ lib/
20
+ lib64/
21
+ parts/
22
+ sdist/
23
+ var/
24
+ wheels/
25
+ share/python-wheels/
26
+ *.egg-info/
27
+ .installed.cfg
28
+ *.egg
29
+ MANIFEST
30
+
31
+ # PyInstaller
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ .python-version
87
+
88
+ # pipenv
89
+ Pipfile.lock
90
+
91
+ # poetry
92
+ poetry.lock
93
+
94
+ # pdm
95
+ .pdm.toml
96
+
97
+ # PEP 582
98
+ __pypackages__/
99
+
100
+ # Celery stuff
101
+ celerybeat-schedule
102
+ celerybeat.pid
103
+
104
+ # SageMath parsed files
105
+ *.sage.py
106
+
107
+ # Environments
108
+ .env
109
+ .venv
110
+ env/
111
+ venv/
112
+ ENV/
113
+ env.bak/
114
+ venv.bak/
115
+
116
+ # Spyder project settings
117
+ .spyderproject
118
+ .spyproject
119
+
120
+ # Rope project settings
121
+ .ropeproject
122
+
123
+ # mkdocs documentation
124
+ /site
125
+
126
+ # mypy
127
+ .mypy_cache/
128
+ .dmypy.json
129
+ dmypy.json
130
+
131
+ # Pyre type checker
132
+ .pyre/
133
+
134
+ # pytype static type analyzer
135
+ .pytype/
136
+
137
+ # Cython debug symbols
138
+ cython_debug/
139
+
140
+ # PyCharm
141
+ .idea/
142
+
143
+ # VS Code
144
+ .vscode/
145
+
146
+ # macOS
147
+ .DS_Store
148
+
149
+ # Google Drive credentials
150
+ credentials.json
151
+ client_secret*.json
152
+ token.pickle
153
+ token.json
154
+
155
+ # SyftBox related
156
+ ~/SyftBox/
157
+ SyftBox/
158
+
159
+ # Temporary files
160
+ *.tmp
161
+ *.bak
162
+ *.swp
163
+ *~
164
+
165
+ # Claude AI settings
166
+ .claude/*
167
+ !.claude/settings.json
168
+ CLAUDE.md
169
+
170
+ # CI test outputs
171
+ test_outputs/
172
+ test_suite_output.log
173
+
174
+
175
+ # Notebooks
176
+ notebooks/e2e/sales_mock.csv
177
+ notebooks/e2e/sales_private.csv
178
+ notebooks/e2e/readme.md
syft_bg-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,276 @@
1
+ Metadata-Version: 2.4
2
+ Name: syft-bg
3
+ Version: 0.2.0
4
+ Summary: Background services TUI dashboard for SyftBox
5
+ Author-email: OpenMined <info@openmined.org>
6
+ License: Apache-2.0
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: click>=8.0.0
9
+ Requires-Dist: google-api-python-client>=2.95.0
10
+ Requires-Dist: google-auth-oauthlib>=1.0.0
11
+ Requires-Dist: google-auth>=2.22.0
12
+ Requires-Dist: jinja2>=3.1.0
13
+ Requires-Dist: pydantic>=2.0.0
14
+ Requires-Dist: pyyaml>=6.0
15
+ Requires-Dist: syft-job>=0.1.23
16
+ Requires-Dist: textual>=0.40.0
17
+ Description-Content-Type: text/markdown
18
+
19
+ # syft-bg
20
+
21
+ Background services for SyftBox: email notifications and auto-approval for peers and jobs.
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install syft-bg
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ```bash
32
+ syft-bg init # Interactive setup wizard
33
+ syft-bg start # Start background services
34
+ syft-bg status # Check what's running
35
+ ```
36
+
37
+ ### Headless Mode
38
+
39
+ ```bash
40
+ # Fully automated (tokens must already exist)
41
+ syft-bg init --email user@example.com --quiet
42
+
43
+ # With custom settings
44
+ syft-bg init \
45
+ --email user@example.com \
46
+ --syftbox-root ~/SyftBox \
47
+ --notify-jobs \
48
+ --approve-jobs \
49
+ --skip-oauth
50
+ ```
51
+
52
+ ### Pythonic API (Notebooks/Scripts)
53
+
54
+ ```python
55
+ import syft_bg
56
+
57
+ result = syft_bg.init(
58
+ email="user@example.com",
59
+ notify_jobs=True,
60
+ approve_jobs=True,
61
+ skip_oauth=True,
62
+ )
63
+
64
+ if result.success:
65
+ print(f"Config saved to {result.config_path}")
66
+ ```
67
+
68
+ ## Commands
69
+
70
+ ```bash
71
+ syft-bg # TUI dashboard
72
+ syft-bg init # Setup wizard (interactive or headless)
73
+ syft-bg setup # Check environment (credentials, tokens, config)
74
+ syft-bg status # Show service status
75
+ syft-bg start [service] # Start all or specific service
76
+ syft-bg stop [service] # Stop all or specific service
77
+ syft-bg restart [service] # Restart all or specific service
78
+ syft-bg logs <service> # View logs (notify or approve)
79
+ syft-bg hash <file> # Generate script hash for auto-approval
80
+ syft-bg install # Install systemd service (auto-start on boot)
81
+ syft-bg uninstall # Remove systemd service
82
+ ```
83
+
84
+ ## CLI Flags for `syft-bg init`
85
+
86
+ | Flag | Description |
87
+ | ---------------------------------------- | ----------------------------------------------- |
88
+ | `--email, -e` | Data Owner email address |
89
+ | `--syftbox-root` | SyftBox directory path |
90
+ | `--yes, -y` | Auto-confirm config overwrite |
91
+ | `--quiet, -q` | No prompts, use defaults (implies --skip-oauth) |
92
+ | `--skip-oauth` | Skip OAuth setup (tokens must exist) |
93
+ | `--notify-jobs/--no-notify-jobs` | Job email notifications |
94
+ | `--notify-peers/--no-notify-peers` | Peer email notifications |
95
+ | `--notify-interval` | Notification check interval (seconds) |
96
+ | `--approve-jobs/--no-approve-jobs` | Auto-approve jobs |
97
+ | `--jobs-peers-only/--no-jobs-peers-only` | Only approve jobs from approved peers |
98
+ | `--approve-peers/--no-approve-peers` | Auto-approve peers |
99
+ | `--approved-domains` | Comma-separated domains for peer approval |
100
+ | `--approve-interval` | Approval check interval (seconds) |
101
+ | `--filenames` | Required filenames (comma-separated) |
102
+ | `--allowed-users` | Allowed users (comma-separated emails) |
103
+ | `--credentials-path` | Path to credentials.json |
104
+ | `--gmail-token` | Path to existing Gmail token |
105
+ | `--drive-token` | Path to existing Drive token |
106
+
107
+ ## Environment Check
108
+
109
+ ```bash
110
+ $ syft-bg setup
111
+
112
+ SYFT-BG ENVIRONMENT CHECK
113
+ ==================================================
114
+
115
+ Checking credentials...
116
+ ✓ credentials.json found at ~/.syft-creds/credentials.json
117
+
118
+ Checking authentication tokens...
119
+ ✓ Gmail token: ~/.syft-creds/gmail_token.json
120
+ ✓ Drive token: ~/.syft-creds/token_do.json
121
+
122
+ Checking configuration...
123
+ ✓ Config file: ~/.syft-creds/config.yaml
124
+
125
+ --------------------------------------------------
126
+ ✅ Environment ready! Run 'syft-bg start' to begin.
127
+ ```
128
+
129
+ ## OAuth Setup
130
+
131
+ Two OAuth flows are required (same credentials.json, separate tokens):
132
+
133
+ 1. **Gmail** → `gmail_token.json` (send email permission)
134
+ 2. **Drive** → `token_do.json` (read/write files permission)
135
+
136
+ **Interactive mode**: Prints OAuth URL, you paste the authorization code back.
137
+
138
+ **Headless mode** (`--quiet`): Skips OAuth, requires tokens to already exist.
139
+
140
+ To get credentials.json:
141
+
142
+ 1. Go to Google Cloud Console → APIs & Services → Credentials
143
+ 2. Create OAuth 2.0 Client ID (Desktop app)
144
+ 3. Download as credentials.json
145
+ 4. Place at `~/.syft-creds/credentials.json`
146
+
147
+ ## Services
148
+
149
+ ### notify
150
+
151
+ Sends email notifications via Gmail when:
152
+
153
+ - A peer requests to connect with you
154
+ - Your peer request is approved by someone
155
+ - A data scientist submits a job to you
156
+ - A job you submitted is approved
157
+ - A job completes (results ready)
158
+
159
+ ### approve
160
+
161
+ Auto-approves peers and jobs based on your config:
162
+
163
+ - **Peers**: Auto-accept connection requests
164
+ - **Jobs**: Auto-approve if script hash and filenames match allowed criteria
165
+
166
+ ## Configuration
167
+
168
+ Config stored at `~/.syft-creds/config.yaml` (Colab: `/content/drive/MyDrive/syft-creds/config.yaml`).
169
+
170
+ ```yaml
171
+ do_email: you@example.com
172
+ syftbox_root: ~/SyftBox
173
+
174
+ notify:
175
+ interval: 30
176
+ monitor_jobs: true
177
+ monitor_peers: true
178
+
179
+ approve:
180
+ interval: 5
181
+ jobs:
182
+ enabled: true
183
+ peers_only: true
184
+ required_filenames:
185
+ - main.py
186
+ - params.json
187
+ required_scripts: {} # sha256 hashes
188
+ allowed_users: [] # empty = all approved peers
189
+ peers:
190
+ enabled: false
191
+ approved_domains:
192
+ - openmined.org
193
+ ```
194
+
195
+ After editing, restart services:
196
+
197
+ ```bash
198
+ syft-bg restart
199
+ ```
200
+
201
+ ## Script Hash Validation
202
+
203
+ Data owners can restrict auto-approval to specific scripts:
204
+
205
+ ```bash
206
+ # Generate hash for a script
207
+ syft-bg hash main.py
208
+ # Output: sha256:a1b2c3d4...
209
+
210
+ # Add to config.yaml
211
+ approve:
212
+ jobs:
213
+ allowed_script_hashes:
214
+ - "sha256:a1b2c3d4..."
215
+ ```
216
+
217
+ Jobs with non-matching scripts require manual approval.
218
+
219
+ ## Systemd Integration
220
+
221
+ Auto-start syft-bg on boot (Linux):
222
+
223
+ ```bash
224
+ syft-bg install # Creates ~/.config/systemd/user/syft-bg.service
225
+ systemctl --user enable syft-bg
226
+ systemctl --user start syft-bg
227
+
228
+ # Check status
229
+ systemctl --user status syft-bg
230
+
231
+ # Remove
232
+ syft-bg uninstall
233
+ ```
234
+
235
+ ## Logs
236
+
237
+ ```bash
238
+ syft-bg logs notify # Notification service logs
239
+ syft-bg logs approve # Approval service logs
240
+ syft-bg logs notify -f # Follow logs in real-time
241
+ ```
242
+
243
+ Log files stored at `~/.syft-creds/logs/`.
244
+
245
+ ## Colab / Jupyter
246
+
247
+ ```python
248
+ !pip install syft-bg
249
+
250
+ import syft_bg
251
+
252
+ # Initialize with Pythonic API
253
+ result = syft_bg.init(
254
+ email="user@example.com",
255
+ notify_jobs=True,
256
+ approve_jobs=True,
257
+ verbose=True, # Show progress
258
+ )
259
+
260
+ # Or use CLI
261
+ !syft-bg init --email user@example.com --quiet
262
+ !syft-bg start
263
+ !syft-bg status
264
+ ```
265
+
266
+ Drive credentials are handled natively in Colab.
267
+
268
+ ## Development
269
+
270
+ Run services in foreground for debugging:
271
+
272
+ ```bash
273
+ syft-bg run --service notify # Run notify in foreground
274
+ syft-bg run --service approve # Run approve in foreground
275
+ syft-bg run --once # Single check cycle, then exit
276
+ ```
@@ -0,0 +1,258 @@
1
+ # syft-bg
2
+
3
+ Background services for SyftBox: email notifications and auto-approval for peers and jobs.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pip install syft-bg
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ syft-bg init # Interactive setup wizard
15
+ syft-bg start # Start background services
16
+ syft-bg status # Check what's running
17
+ ```
18
+
19
+ ### Headless Mode
20
+
21
+ ```bash
22
+ # Fully automated (tokens must already exist)
23
+ syft-bg init --email user@example.com --quiet
24
+
25
+ # With custom settings
26
+ syft-bg init \
27
+ --email user@example.com \
28
+ --syftbox-root ~/SyftBox \
29
+ --notify-jobs \
30
+ --approve-jobs \
31
+ --skip-oauth
32
+ ```
33
+
34
+ ### Pythonic API (Notebooks/Scripts)
35
+
36
+ ```python
37
+ import syft_bg
38
+
39
+ result = syft_bg.init(
40
+ email="user@example.com",
41
+ notify_jobs=True,
42
+ approve_jobs=True,
43
+ skip_oauth=True,
44
+ )
45
+
46
+ if result.success:
47
+ print(f"Config saved to {result.config_path}")
48
+ ```
49
+
50
+ ## Commands
51
+
52
+ ```bash
53
+ syft-bg # TUI dashboard
54
+ syft-bg init # Setup wizard (interactive or headless)
55
+ syft-bg setup # Check environment (credentials, tokens, config)
56
+ syft-bg status # Show service status
57
+ syft-bg start [service] # Start all or specific service
58
+ syft-bg stop [service] # Stop all or specific service
59
+ syft-bg restart [service] # Restart all or specific service
60
+ syft-bg logs <service> # View logs (notify or approve)
61
+ syft-bg hash <file> # Generate script hash for auto-approval
62
+ syft-bg install # Install systemd service (auto-start on boot)
63
+ syft-bg uninstall # Remove systemd service
64
+ ```
65
+
66
+ ## CLI Flags for `syft-bg init`
67
+
68
+ | Flag | Description |
69
+ | ---------------------------------------- | ----------------------------------------------- |
70
+ | `--email, -e` | Data Owner email address |
71
+ | `--syftbox-root` | SyftBox directory path |
72
+ | `--yes, -y` | Auto-confirm config overwrite |
73
+ | `--quiet, -q` | No prompts, use defaults (implies --skip-oauth) |
74
+ | `--skip-oauth` | Skip OAuth setup (tokens must exist) |
75
+ | `--notify-jobs/--no-notify-jobs` | Job email notifications |
76
+ | `--notify-peers/--no-notify-peers` | Peer email notifications |
77
+ | `--notify-interval` | Notification check interval (seconds) |
78
+ | `--approve-jobs/--no-approve-jobs` | Auto-approve jobs |
79
+ | `--jobs-peers-only/--no-jobs-peers-only` | Only approve jobs from approved peers |
80
+ | `--approve-peers/--no-approve-peers` | Auto-approve peers |
81
+ | `--approved-domains` | Comma-separated domains for peer approval |
82
+ | `--approve-interval` | Approval check interval (seconds) |
83
+ | `--filenames` | Required filenames (comma-separated) |
84
+ | `--allowed-users` | Allowed users (comma-separated emails) |
85
+ | `--credentials-path` | Path to credentials.json |
86
+ | `--gmail-token` | Path to existing Gmail token |
87
+ | `--drive-token` | Path to existing Drive token |
88
+
89
+ ## Environment Check
90
+
91
+ ```bash
92
+ $ syft-bg setup
93
+
94
+ SYFT-BG ENVIRONMENT CHECK
95
+ ==================================================
96
+
97
+ Checking credentials...
98
+ ✓ credentials.json found at ~/.syft-creds/credentials.json
99
+
100
+ Checking authentication tokens...
101
+ ✓ Gmail token: ~/.syft-creds/gmail_token.json
102
+ ✓ Drive token: ~/.syft-creds/token_do.json
103
+
104
+ Checking configuration...
105
+ ✓ Config file: ~/.syft-creds/config.yaml
106
+
107
+ --------------------------------------------------
108
+ ✅ Environment ready! Run 'syft-bg start' to begin.
109
+ ```
110
+
111
+ ## OAuth Setup
112
+
113
+ Two OAuth flows are required (same credentials.json, separate tokens):
114
+
115
+ 1. **Gmail** → `gmail_token.json` (send email permission)
116
+ 2. **Drive** → `token_do.json` (read/write files permission)
117
+
118
+ **Interactive mode**: Prints OAuth URL, you paste the authorization code back.
119
+
120
+ **Headless mode** (`--quiet`): Skips OAuth, requires tokens to already exist.
121
+
122
+ To get credentials.json:
123
+
124
+ 1. Go to Google Cloud Console → APIs & Services → Credentials
125
+ 2. Create OAuth 2.0 Client ID (Desktop app)
126
+ 3. Download as credentials.json
127
+ 4. Place at `~/.syft-creds/credentials.json`
128
+
129
+ ## Services
130
+
131
+ ### notify
132
+
133
+ Sends email notifications via Gmail when:
134
+
135
+ - A peer requests to connect with you
136
+ - Your peer request is approved by someone
137
+ - A data scientist submits a job to you
138
+ - A job you submitted is approved
139
+ - A job completes (results ready)
140
+
141
+ ### approve
142
+
143
+ Auto-approves peers and jobs based on your config:
144
+
145
+ - **Peers**: Auto-accept connection requests
146
+ - **Jobs**: Auto-approve if script hash and filenames match allowed criteria
147
+
148
+ ## Configuration
149
+
150
+ Config stored at `~/.syft-creds/config.yaml` (Colab: `/content/drive/MyDrive/syft-creds/config.yaml`).
151
+
152
+ ```yaml
153
+ do_email: you@example.com
154
+ syftbox_root: ~/SyftBox
155
+
156
+ notify:
157
+ interval: 30
158
+ monitor_jobs: true
159
+ monitor_peers: true
160
+
161
+ approve:
162
+ interval: 5
163
+ jobs:
164
+ enabled: true
165
+ peers_only: true
166
+ required_filenames:
167
+ - main.py
168
+ - params.json
169
+ required_scripts: {} # sha256 hashes
170
+ allowed_users: [] # empty = all approved peers
171
+ peers:
172
+ enabled: false
173
+ approved_domains:
174
+ - openmined.org
175
+ ```
176
+
177
+ After editing, restart services:
178
+
179
+ ```bash
180
+ syft-bg restart
181
+ ```
182
+
183
+ ## Script Hash Validation
184
+
185
+ Data owners can restrict auto-approval to specific scripts:
186
+
187
+ ```bash
188
+ # Generate hash for a script
189
+ syft-bg hash main.py
190
+ # Output: sha256:a1b2c3d4...
191
+
192
+ # Add to config.yaml
193
+ approve:
194
+ jobs:
195
+ allowed_script_hashes:
196
+ - "sha256:a1b2c3d4..."
197
+ ```
198
+
199
+ Jobs with non-matching scripts require manual approval.
200
+
201
+ ## Systemd Integration
202
+
203
+ Auto-start syft-bg on boot (Linux):
204
+
205
+ ```bash
206
+ syft-bg install # Creates ~/.config/systemd/user/syft-bg.service
207
+ systemctl --user enable syft-bg
208
+ systemctl --user start syft-bg
209
+
210
+ # Check status
211
+ systemctl --user status syft-bg
212
+
213
+ # Remove
214
+ syft-bg uninstall
215
+ ```
216
+
217
+ ## Logs
218
+
219
+ ```bash
220
+ syft-bg logs notify # Notification service logs
221
+ syft-bg logs approve # Approval service logs
222
+ syft-bg logs notify -f # Follow logs in real-time
223
+ ```
224
+
225
+ Log files stored at `~/.syft-creds/logs/`.
226
+
227
+ ## Colab / Jupyter
228
+
229
+ ```python
230
+ !pip install syft-bg
231
+
232
+ import syft_bg
233
+
234
+ # Initialize with Pythonic API
235
+ result = syft_bg.init(
236
+ email="user@example.com",
237
+ notify_jobs=True,
238
+ approve_jobs=True,
239
+ verbose=True, # Show progress
240
+ )
241
+
242
+ # Or use CLI
243
+ !syft-bg init --email user@example.com --quiet
244
+ !syft-bg start
245
+ !syft-bg status
246
+ ```
247
+
248
+ Drive credentials are handled natively in Colab.
249
+
250
+ ## Development
251
+
252
+ Run services in foreground for debugging:
253
+
254
+ ```bash
255
+ syft-bg run --service notify # Run notify in foreground
256
+ syft-bg run --service approve # Run approve in foreground
257
+ syft-bg run --once # Single check cycle, then exit
258
+ ```