Skip to content

Commit 2e6ba9c

Browse files
author
Faxbot Agent
committed
fix(tests): use configurable TEST_FAX_NUMBER for all smoke tests
- Added test_fax_number to Settings model (from TEST_FAX_NUMBER env var) - Exposed test_fax_number in /admin/config endpoint - Updated Diagnostics.tsx to load and use TEST_FAX_NUMBER - Updated OutboundSmokeTests.tsx to load and use TEST_FAX_NUMBER - Show helpful error when TEST_FAX_NUMBER not configured - Display configured test number in UI instead of fake +15555550123 This ensures smoke tests work with real providers (Sinch, HumbleFax, etc) instead of failing with fake numbers. Users configure their own test-capable fax number via TEST_FAX_NUMBER environment variable.
1 parent 46112ad commit 2e6ba9c

File tree

9 files changed

+92
-29
lines changed

9 files changed

+92
-29
lines changed

README.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,19 @@
22
<img src="assets/faxbot_full_logo.png" alt="Faxbot logo" width="100%" />
33
</p>
44
<p align="center">
5-
<a href="https://dmontgomery40.github.io/Faxbot/">
5+
<a href="https://docs.faxbot.net/">
66
<img alt="View the Documentation" src="https://img.shields.io/badge/Docs-Faxbot-2b5fff?style=for-the-badge">
77
</a>
88
</p>
99

1010
<p align="center">
11-
<a href="https://faxbot.net">
11+
<a href="https://faxbot.net/">
1212
<img alt="Visit the Website" src="https://img.shields.io/badge/Website-faxbot.net-00c853?style=for-the-badge">
1313
</a>
1414
</p>
1515

1616
<p align="center">
17-
<a href="https://faxbot.net/admin-demo">
17+
<a href="https://faxbot.net/admin-demo/">
1818
<img alt="UI Demo" src="https://img.shields.io/badge/UI%20Demo-Admin%20Console-ff9800?style=for-the-badge">
1919
</a>
2020
</p>
@@ -68,23 +68,22 @@ The iOS companion lets you send faxes and check status from your phone. Email da
6868
## SDKs
6969
- Python: `pip install faxbot`
7070
- Node.js: `npm install faxbot`
71-
[SDK Usage](docs/SDKS.md)
71+
[SDK Usage](https://github.com/dmontgomery40/faxbot/blob/auto-tunnel/docs/SDKS.md)
7272

7373
## Architecture highlights
7474
- Traits‑first capabilities: `/admin/providers` and `/admin/config` expose active providers + traits; UI and API gate features by traits.
7575
- Canonical event & error model: normalized inbound/outbound events, status mapping, and standard error codes.
7676
- Provider adapters: clean boundaries for verify_webhook/parse_inbound/send/status/cancel.
7777

7878
Docs:
79-
- [Canonical Events](docs/api/canonical_events.md)
80-
- [MCP Integration](docs/MCP_INTEGRATION.md)
81-
- [API Reference](docs/API_REFERENCE.md)
79+
- [Canonical Events](https://github.com/dmontgomery40/faxbot/blob/auto-tunnel/docs/api/canonical_events.md)
80+
- [MCP Integration](https://github.com/dmontgomery40/faxbot/blob/auto-tunnel/docs/MCP_INTEGRATION.md)
81+
- [API Reference](https://github.com/dmontgomery40/faxbot/blob/auto-tunnel/docs/API_REFERENCE.md)
8282

8383
## Security
8484
- Use `X-API-Key` (multi‑key) for auth.
8585
- Enforce HTTPS and HMAC signature verification for cloud webhooks.
8686
- No PHI in logs; only IDs/metadata are surfaced.
8787

8888
## Contributing
89-
See [CONTRIBUTING.md](CONTRIBUTING.md). Please open issues/PRs; this project is GUI‑first and traits‑first—avoid backend‑name checks in new code.
90-
89+
See [CONTRIBUTING.md](https://github.com/dmontgomery40/faxbot/blob/auto-tunnel/CONTRIBUTING.md). Please open issues/PRs; this project is GUI‑first and traits‑first—avoid backend‑name checks in new code.

api/admin_ui/src/components/Diagnostics.tsx

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ function Diagnostics({ client, onNavigate, docsBase }: DiagnosticsProps) {
6969
const [testStatus, setTestStatus] = useState<string | null>(null);
7070
const [expandedSections, setExpandedSections] = useState<string[]>(['summary']);
7171
const [anchors, setAnchors] = useState<Record<string, string>>({});
72+
const [testNumber, setTestNumber] = useState<string>('');
7273
// Third‑party precise links (fallback)
7374
const thirdParty: Record<string, string> = {
7475
// Sinch
@@ -204,6 +205,18 @@ function Diagnostics({ client, onNavigate, docsBase }: DiagnosticsProps) {
204205
loadAnchors();
205206
}, [docsBase, active?.outbound, active?.inbound]);
206207

208+
// Load test fax number from config
209+
useEffect(() => {
210+
(async () => {
211+
try {
212+
const cfg = await client.getConfig();
213+
setTestNumber(cfg?.test_fax_number || '');
214+
} catch {
215+
// ignore
216+
}
217+
})();
218+
}, [client]);
219+
207220
const runDiagnostics = async () => {
208221
try {
209222
setError(null);
@@ -605,14 +618,18 @@ function Diagnostics({ client, onNavigate, docsBase }: DiagnosticsProps) {
605618
};
606619

607620
const runSendTestFax = async () => {
621+
if (!testNumber) {
622+
setError('TEST_FAX_NUMBER not configured. Set it in .env to your own fax-capable number.');
623+
return;
624+
}
608625
try {
609626
setError(null);
610627
setTestSending(true);
611628
setTestJobId(null);
612629
setTestStatus(null);
613630
const blob = new Blob(["Faxbot test"], { type: 'text/plain' });
614631
const file = new File([blob], 'test.txt', { type: 'text/plain' });
615-
const result = await client.sendFax('+15555550123', file);
632+
const result = await client.sendFax(testNumber, file);
616633
setTestJobId(result.id);
617634
setTestStatus(result.status);
618635

@@ -642,14 +659,18 @@ function Diagnostics({ client, onNavigate, docsBase }: DiagnosticsProps) {
642659

643660
// Send Test TXT (simple text → backend converts to PDF)
644661
const runSendTestTxtFax = async () => {
662+
if (!testNumber) {
663+
setError('TEST_FAX_NUMBER not configured. Set it in .env to your own fax-capable number.');
664+
return;
665+
}
645666
try {
646667
setError(null);
647668
setTestSendingTxt(true);
648669
setTestJobId(null);
649670
setTestStatus(null);
650671
const blob = new Blob(["Faxbot test TXT\nHello from Admin Console"], { type: 'text/plain' });
651672
const file = new File([blob], 'faxbot_test.txt', { type: 'text/plain' });
652-
const result = await client.sendFax('+15555550123', file);
673+
const result = await client.sendFax(testNumber, file);
653674
setTestJobId(result.id);
654675
setTestStatus(result.status);
655676
let attempts = 0;
@@ -716,6 +737,10 @@ function Diagnostics({ client, onNavigate, docsBase }: DiagnosticsProps) {
716737

717738
// Send Test Image (PDF) — generates a simple PDF with text to exercise raster path
718739
const runSendTestImageFax = async () => {
740+
if (!testNumber) {
741+
setError('TEST_FAX_NUMBER not configured. Set it in .env to your own fax-capable number.');
742+
return;
743+
}
719744
try {
720745
setError(null);
721746
setTestSendingImg(true);
@@ -727,7 +752,7 @@ function Diagnostics({ client, onNavigate, docsBase }: DiagnosticsProps) {
727752
new Uint8Array(ab).set(bytes);
728753
const blob = new Blob([ab], { type: 'application/pdf' });
729754
const file = new File([blob], 'faxbot_test_image.pdf', { type: 'application/pdf' });
730-
const result = await client.sendFax('+15555550123', file);
755+
const result = await client.sendFax(testNumber, file);
731756
setTestJobId(result.id);
732757
setTestStatus(result.status);
733758
let attempts = 0;
@@ -895,7 +920,9 @@ function Diagnostics({ client, onNavigate, docsBase }: DiagnosticsProps) {
895920
)}
896921
</Box>
897922
<Typography variant="caption" color="text.secondary">
898-
Uses your current backend settings. For cloud backends without valid credentials this will fail fast with an error.
923+
{testNumber
924+
? `Test destination: ${testNumber} (configured via TEST_FAX_NUMBER). Uses your current backend settings.`
925+
: 'Set TEST_FAX_NUMBER in .env to your own fax-capable number to enable tests. Fake numbers do not work with real providers.'}
899926
</Typography>
900927
</Stack>
901928
</ResponsiveFormSection>

api/admin_ui/src/components/EventStream.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,15 @@ const EventStream: React.FC<EventStreamProps> = ({ client }) => {
368368
secondary={
369369
<Box>
370370
<Typography variant="caption" color="text.secondary" display="block">
371-
{format(new Date(event.occurred_at), 'MMM dd, HH:mm:ss.SSS')}
371+
{new Date(event.occurred_at).toLocaleString('en-US', {
372+
month: 'short',
373+
day: '2-digit',
374+
hour: '2-digit',
375+
minute: '2-digit',
376+
second: '2-digit',
377+
fractionalSecondDigits: 3,
378+
hour12: false
379+
})}
372380
{event.job_id && ` • Job: ${event.job_id}`}
373381
{event.external_id && ` • Ext: ${event.external_id}`}
374382
{event.correlation_id && ` • Correlation: ${event.correlation_id}`}

api/admin_ui/src/components/OutboundSmokeTests.tsx

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from 'react';
1+
import { useState, useEffect } from 'react';
22
import {
33
Box,
44
Typography,
@@ -74,10 +74,23 @@ export default function OutboundSmokeTests({ client, canSend = true }: OutboundS
7474
const [testJobs, setTestJobs] = useState<TestJob[]>([]);
7575
const [loading, setLoading] = useState<Record<string, boolean>>({});
7676
const [expandedJobs, setExpandedJobs] = useState<Set<string>>(new Set());
77+
const [testNumber, setTestNumber] = useState<string>('');
7778

7879
const activeOutbound = active?.outbound || '';
7980
const providerName = getProviderDisplayName(activeOutbound);
8081

82+
// Load test fax number from config
83+
useEffect(() => {
84+
(async () => {
85+
try {
86+
const cfg = await client.getConfig();
87+
setTestNumber(cfg?.test_fax_number || '');
88+
} catch {
89+
// ignore
90+
}
91+
})();
92+
}, [client]);
93+
8194
const getStatusColor = (status: string): 'success' | 'error' | 'warning' | 'info' | 'default' => {
8295
switch (status.toLowerCase()) {
8396
case 'success':
@@ -199,11 +212,23 @@ export default function OutboundSmokeTests({ client, canSend = true }: OutboundS
199212
};
200213

201214
const runSmokeTest = async (testType: 'txt' | 'pdf' | 'image') => {
215+
if (!testNumber) {
216+
const errorJob: TestJob = {
217+
id: `error-${Date.now()}`,
218+
type: testType,
219+
status: 'failed',
220+
error: 'TEST_FAX_NUMBER not configured. Set it in .env to your own fax-capable number.',
221+
created_at: new Date().toISOString(),
222+
};
223+
setTestJobs(prev => [errorJob, ...prev.slice(0, 9)]);
224+
return;
225+
}
226+
202227
try {
203228
setLoading(prev => ({ ...prev, [testType]: true }));
204229

205230
const testFile = createTestFile(testType);
206-
const result = await client.sendFax('+15555550123', testFile);
231+
const result = await client.sendFax(testNumber, testFile);
207232

208233
const newJob: TestJob = {
209234
id: result.id,
@@ -339,7 +364,9 @@ export default function OutboundSmokeTests({ client, canSend = true }: OutboundS
339364
</Typography>
340365
</Box>
341366
<Typography variant="body2">
342-
Tests use destination +15555550123 (safe test number)
367+
{testNumber
368+
? `Test destination: ${testNumber} (configured via TEST_FAX_NUMBER)`
369+
: 'Configure TEST_FAX_NUMBER in .env to enable tests'}
343370
</Typography>
344371
</Alert>
345372

api/app/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ class Settings(BaseModel):
147147
humblefax_webhook_secret: str = Field(default_factory=lambda: os.getenv("HUMBLEFAX_WEBHOOK_SECRET", ""))
148148
humblefax_callback_base: str = Field(default_factory=lambda: os.getenv("HUMBLEFAX_CALLBACK_BASE", ""))
149149

150+
# Testing - use your own fax-capable number for smoke tests (must be valid E.164)
151+
test_fax_number: str = Field(default_factory=lambda: os.getenv("TEST_FAX_NUMBER", ""))
152+
150153
# Storage backend for inbound artifacts
151154
storage_backend: str = Field(default_factory=lambda: os.getenv("STORAGE_BACKEND", "local")) # local | s3
152155
s3_bucket: str = Field(default_factory=lambda: os.getenv("S3_BUCKET", ""))

api/app/main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,6 +1273,7 @@ def get_admin_config():
12731273
"sip_ami_password_default": (settings.ami_password == "changeme"),
12741274
},
12751275
"public_api_url": settings.public_api_url,
1276+
"test_fax_number": settings.test_fax_number or "",
12761277
}
12771278
# v3 plugins status (feature-gated)
12781279
if settings.feature_v3_plugins:

docs/SECURITY.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,9 @@ Configuration and guidance for HIPAA‑aligned deployments and OAuth/OIDC setup.
2222

2323
Recommended reading
2424
- [Authentication (API Keys)](/security/authentication)
25-
- [HIPAA Requirements](../HIPAA_REQUIREMENTS.md)
26-
- [OAuth/OIDC Setup](OAUTH_SETUP.md)
25+
- [HIPAA Requirements](https://github.com/dmontgomery40/faxbot/blob/auto-tunnel/HIPAA_REQUIREMENTS.md)
26+
- [OAuth/OIDC Setup](https://github.com/dmontgomery40/faxbot/blob/auto-tunnel/docs/OAUTH_SETUP.md)
2727
- [Authentication (API Keys)](/Faxbot/security/authentication.html)
2828
- [OAuth/OIDC Setup](/Faxbot/security/oauth-setup.html)
2929
- [Compliance Overview (faxbot.net)](https://faxbot.net/compliance/)
3030
- [Business Associate Agreement (PDF)](https://faxbot.net/compliance/business-associate-agreement.pdf)
31-

docs/archive/legacy/SECURITY.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,9 @@ Configuration and guidance for HIPAA‑aligned deployments and OAuth/OIDC setup.
2222

2323
Recommended reading
2424
- [Authentication (API Keys)](/security/authentication)
25-
- [HIPAA Requirements](../HIPAA_REQUIREMENTS.md)
26-
- [OAuth/OIDC Setup](OAUTH_SETUP.md)
25+
- [HIPAA Requirements](https://github.com/dmontgomery40/faxbot/blob/auto-tunnel/HIPAA_REQUIREMENTS.md)
26+
- [OAuth/OIDC Setup](https://github.com/dmontgomery40/faxbot/blob/auto-tunnel/docs/OAUTH_SETUP.md)
2727
- [Authentication (API Keys)](/Faxbot/security/authentication.html)
2828
- [OAuth/OIDC Setup](/Faxbot/security/oauth-setup.html)
2929
- [Compliance Overview (faxbot.net)](https://faxbot.net/compliance/)
3030
- [Business Associate Agreement (PDF)](https://faxbot.net/compliance/business-associate-agreement.pdf)
31-

docs/openapi-cors.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,27 @@ <h1>Faxbot OpenAPI Specification</h1>
3030
<p>Access the Faxbot API specification without CORS restrictions:</p>
3131

3232
<h2>🔗 Direct Links</h2>
33-
<a href="https://raw.githubusercontent.com/DMontgomery40/Faxbot/docs-jekyll-site/docs/openapi.yaml" class="button">
33+
<a href="https://raw.githubusercontent.com/dmontgomery40/faxbot/auto-tunnel/docs/openapi.yaml" class="button">
3434
📄 Raw YAML (No CORS)
3535
</a>
36-
<a href="https://petstore.swagger.io/?url=https://raw.githubusercontent.com/DMontgomery40/Faxbot/docs-jekyll-site/docs/openapi.yaml" class="button">
36+
<a href="https://petstore.swagger.io/?url=https://raw.githubusercontent.com/dmontgomery40/faxbot/auto-tunnel/docs/openapi.yaml" class="button">
3737
🔍 Swagger UI
3838
</a>
39-
<a href="https://editor.swagger.io/?url=https://raw.githubusercontent.com/DMontgomery40/Faxbot/docs-jekyll-site/docs/openapi.yaml" class="button">
39+
<a href="https://editor.swagger.io/?url=https://raw.githubusercontent.com/dmontgomery40/faxbot/auto-tunnel/docs/openapi.yaml" class="button">
4040
✏️ Swagger Editor
4141
</a>
4242

4343
<h2>📋 For Copy/Paste</h2>
4444
<p>Use this URL in any OpenAPI tool:</p>
45-
<pre><code>https://raw.githubusercontent.com/DMontgomery40/Faxbot/docs-jekyll-site/docs/openapi.yaml</code></pre>
45+
<pre><code>https://raw.githubusercontent.com/dmontgomery40/faxbot/auto-tunnel/docs/openapi.yaml</code></pre>
4646

4747
<h2>🛠️ Tool-Specific Instructions</h2>
4848

4949
<h3>Postman</h3>
5050
<ol>
5151
<li>Open Postman</li>
5252
<li>Click "Import" → "Link"</li>
53-
<li>Paste: <code>https://raw.githubusercontent.com/DMontgomery40/Faxbot/docs-jekyll-site/docs/openapi.yaml</code></li>
53+
<li>Paste: <code>https://raw.githubusercontent.com/dmontgomery40/faxbot/auto-tunnel/docs/openapi.yaml</code></li>
5454
<li>Click "Continue" → "Import"</li>
5555
</ol>
5656

@@ -78,7 +78,7 @@ <h2>🔧 Why This Works</h2>
7878

7979
<script>
8080
// Test if the raw URL is accessible
81-
fetch('https://raw.githubusercontent.com/DMontgomery40/Faxbot/docs-jekyll-site/docs/openapi.yaml')
81+
fetch('https://raw.githubusercontent.com/dmontgomery40/faxbot/auto-tunnel/docs/openapi.yaml')
8282
.then(response => {
8383
if (response.ok) {
8484
document.getElementById('status').innerHTML =

0 commit comments

Comments
 (0)