@reliabilityworks/core 0.5.0 → 0.7.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reliabilityworks/core",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
@@ -0,0 +1,29 @@
1
+ const assert = require('node:assert/strict')
2
+ const fs = require('node:fs/promises')
3
+ const path = require('node:path')
4
+ const test = require('node:test')
5
+
6
+ const { scanProject } = require('../dist/index.js')
7
+
8
+ test('astro ruleset has fixture coverage', async () => {
9
+ const fixtureRoot = path.join(__dirname, 'fixtures', 'monorepo', 'apps', 'astro')
10
+ const rulesPath = path.join(__dirname, '..', '..', 'rulesets', 'astro', 'rules.json')
11
+
12
+ const raw = await fs.readFile(rulesPath, 'utf8')
13
+ const rules = JSON.parse(raw)
14
+
15
+ assert.ok(Array.isArray(rules))
16
+ assert.ok(rules.length >= 60, `Expected at least 60 astro rules, got ${rules.length}`)
17
+
18
+ const expectedIds = rules.map((r) => r.id)
19
+ const result = await scanProject({
20
+ rootDir: fixtureRoot,
21
+ pathBaseDir: fixtureRoot,
22
+ additionalRules: rules,
23
+ })
24
+
25
+ const foundIds = new Set(result.findings.map((finding) => finding.ruleId))
26
+ const missing = expectedIds.filter((id) => !foundIds.has(id))
27
+
28
+ assert.equal(missing.length, 0, `Missing astro fixture coverage for: ${missing.join(', ')}`)
29
+ })
@@ -0,0 +1,75 @@
1
+ ---
2
+ const a = "document.cookie"
3
+ const b = "response.headers.set('Location', '/login')"
4
+ const c = "Authorization: Basic dXNlcjpwYXNz"
5
+ const d = "Authorization: Bearer not-a-real-token"
6
+ const e = "Astro.url.searchParams.get('next')"
7
+ const f = "Astro.cookies.get('sid')"
8
+ const g = "Astro.cookies.set('sid', '1')"
9
+ const h = "Astro.redirect('/login')"
10
+ const i = "/graphql"
11
+ const j = "eval(\"alert(1)\")"
12
+ const k = "new Function('return 1')"
13
+ const l = "insertAdjacentHTML('<div>')"
14
+ const m = "document.write('<div>')"
15
+ const n = "parseFromString('<div>')"
16
+ const o = "localStorage"
17
+ const p = "sessionStorage"
18
+ const q = "addEventListener('message'"
19
+ const r = ".postMessage('hello')"
20
+ const s = "fetch('http://example.com')"
21
+ const t = "el.innerHTML = '<div>unsafe</div>'"
22
+ ---
23
+
24
+ <head>
25
+ <meta
26
+ http-equiv="Content-Security-Policy"
27
+ content="script-src 'unsafe-inline' 'unsafe-eval' http://example.com"
28
+ />
29
+ <meta http-equiv="refresh" content="0;url=http://example.com" />
30
+ </head>
31
+
32
+ <div
33
+ style="color: red"
34
+ onclick="alert(1)"
35
+ onerror="alert(1)"
36
+ onload="alert(1)"
37
+ onmouseover="1"
38
+ onfocus="1"
39
+ onblur="1"
40
+ onchange="1"
41
+ onsubmit="1"
42
+ onkeyup="1"
43
+ onkeydown="1"
44
+ onkeypress="1"
45
+ onmouseenter="1"
46
+ onmouseleave="1"
47
+ ></div>
48
+
49
+ <a href="javascript:alert(1)" target="_blank" referrerpolicy="unsafe-url">x</a>
50
+
51
+ <img src="http://example.com/x.png" onerror="alert(1)" />
52
+ <img src="data:image/svg+xml,<svg onload=alert(1)></svg>" />
53
+
54
+ <iframe src="http://example.com"></iframe>
55
+ <iframe
56
+ src="http://example.com"
57
+ srcdoc="<img src=x onerror=alert(1)>"
58
+ sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox allow-top-navigation allow-forms"
59
+ ></iframe>
60
+
61
+ <object data="http://example.com"></object>
62
+ <embed src="http://example.com"></embed>
63
+
64
+ <svg></svg>
65
+ <math></math>
66
+
67
+ <script src="http://example.com/app.js"></script>
68
+ <script src="data:text/javascript,alert(1)"></script>
69
+ <link rel="stylesheet" href="http://example.com/app.css" />
70
+
71
+ <video src="http://example.com/v.mp4"></video>
72
+ <audio src="http://example.com/a.mp3"></audio>
73
+
74
+ <input type="password" />
75
+ <input type="file" />
@@ -5,6 +5,29 @@
5
5
  <dict>
6
6
  <key>NSAllowsArbitraryLoads</key>
7
7
  <true />
8
+ <key>NSAllowsArbitraryLoadsInWebContent</key>
9
+ <true />
10
+ <key>NSAllowsArbitraryLoadsForMedia</key>
11
+ <true />
12
+ <key>NSAllowsArbitraryLoadsForWebContent</key>
13
+ <true />
14
+ <key>NSAllowsLocalNetworking</key>
15
+ <true />
16
+ <key>NSExceptionDomains</key>
17
+ <dict>
18
+ <key>example.com</key>
19
+ <dict>
20
+ <key>NSExceptionAllowsInsecureHTTPLoads</key>
21
+ <true />
22
+ <key>NSExceptionMinimumTLSVersion</key>
23
+ <string>TLSv1.0</string>
24
+ </dict>
25
+ </dict>
8
26
  </dict>
27
+
28
+ <key>UIFileSharingEnabled</key>
29
+ <true />
30
+ <key>LSSupportsOpeningDocumentsInPlace</key>
31
+ <true />
9
32
  </dict>
10
33
  </plist>
@@ -1,3 +1,29 @@
1
- <manifest>
2
- <application android:usesCleartextTraffic="true"></application>
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.rn">
2
+ <uses-permission android:name="android.permission.CAMERA" />
3
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
4
+ <uses-permission android:name="android.permission.READ_SMS" />
5
+ <uses-permission android:name="android.permission.SEND_SMS" />
6
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
7
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
8
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
9
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
10
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
11
+ <uses-permission android:name="android.permission.READ_CALL_LOG" />
12
+ <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
13
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
14
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
15
+ <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
16
+ <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
17
+ <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
18
+
19
+ <application
20
+ android:usesCleartextTraffic="true"
21
+ android:debuggable="true"
22
+ android:allowBackup="true"
23
+ android:networkSecurityConfig="@xml/network_security_config"
24
+ android:requestLegacyExternalStorage="true">
25
+ <activity android:name=".MainActivity" android:exported="true" />
26
+ <receiver android:name=".MyReceiver" android:exported="true" />
27
+ <service android:name=".MyService" android:exported="true" />
28
+ </application>
3
29
  </manifest>
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <plist version="1.0">
3
+ <dict>
4
+ <key>com.apple.developer.associated-domains</key>
5
+ <array>
6
+ <string>applinks:example.com</string>
7
+ </array>
8
+
9
+ <key>get-task-allow</key>
10
+ <true />
11
+
12
+ <key>keychain-access-groups</key>
13
+ <array>
14
+ <string>$(AppIdentifierPrefix)com.example.rn</string>
15
+ </array>
16
+ </dict>
17
+ </plist>
@@ -0,0 +1,38 @@
1
+ export function triggerReactNativeRulesFixture() {
2
+ const snippets = [
3
+ 'allowDeviceCredentials: true',
4
+ '__DEV__',
5
+ 'debug: true',
6
+ "AsyncStorage.setItem('token', 'secret')",
7
+ "AsyncStorage.getItem('token')",
8
+ "fetch('http://example.com')",
9
+ "baseURL: 'http://example.com'",
10
+ "console.log('token', 'secret')",
11
+ 'file://etc/passwd',
12
+ "Clipboard.setString('secret')",
13
+ 'Pasteboard',
14
+ 'Linking.getInitialURL()',
15
+ "Linking.openURL('http://example.com')",
16
+ "Linking.addEventListener('url', () => {})",
17
+ 'remote debugging',
18
+ 'Debug JS Remotely',
19
+ 'new MMKV()',
20
+ 'kSecAttrAccessibleAlways',
21
+ 'MD5',
22
+ 'SHA1',
23
+ 'Math.random()',
24
+ "originWhitelist = ['*']",
25
+ "mixedContentMode = 'always'",
26
+ 'javaScriptEnabled = { true }',
27
+ 'domStorageEnabled = { true }',
28
+ "injectedJavaScript = '...';",
29
+ 'sharedCookiesEnabled = {true}',
30
+ 'thirdPartyCookiesEnabled = {true}',
31
+ 'onMessage = () => {}',
32
+ "postMessage('hello')",
33
+ "uri: 'http://example.com'",
34
+ 'allowlist',
35
+ ]
36
+
37
+ return snippets.join('\n')
38
+ }
@@ -0,0 +1,33 @@
1
+ const assert = require('node:assert/strict')
2
+ const fs = require('node:fs/promises')
3
+ const path = require('node:path')
4
+ const test = require('node:test')
5
+
6
+ const { scanProject } = require('../dist/index.js')
7
+
8
+ test('react-native ruleset has fixture coverage', async () => {
9
+ const fixtureRoot = path.join(__dirname, 'fixtures', 'monorepo', 'apps', 'rn')
10
+ const rulesPath = path.join(__dirname, '..', '..', 'rulesets', 'react-native', 'rules.json')
11
+
12
+ const raw = await fs.readFile(rulesPath, 'utf8')
13
+ const rules = JSON.parse(raw)
14
+
15
+ assert.ok(Array.isArray(rules))
16
+ assert.ok(rules.length >= 60, `Expected at least 60 react-native rules, got ${rules.length}`)
17
+
18
+ const expectedIds = rules.map((r) => r.id)
19
+ const result = await scanProject({
20
+ rootDir: fixtureRoot,
21
+ pathBaseDir: fixtureRoot,
22
+ additionalRules: rules,
23
+ })
24
+
25
+ const foundIds = new Set(result.findings.map((finding) => finding.ruleId))
26
+ const missing = expectedIds.filter((id) => !foundIds.has(id))
27
+
28
+ assert.equal(
29
+ missing.length,
30
+ 0,
31
+ `Missing react-native fixture coverage for: ${missing.join(', ')}`,
32
+ )
33
+ })