@goodandready/dsh-moa 0.2.59 → 0.2.60

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/lib/access.js CHANGED
@@ -136,6 +136,19 @@ export function getReadRejectionStatus(req, ctx = null) {
136
136
  return 403
137
137
  }
138
138
 
139
+ const host = String(req.headers.host || '').trim().toLowerCase()
140
+ const origin = req.headers.origin
141
+ if (origin && origin !== 'null') {
142
+ try {
143
+ const u = new URL(origin)
144
+ if (host && u.host.toLowerCase() !== host) {
145
+ return 403
146
+ }
147
+ } catch {
148
+ return 403
149
+ }
150
+ }
151
+
139
152
  // 2. Reverse-proxy / forwarded client verification (#257)
140
153
  const xff = req.headers['x-forwarded-for']
141
154
  let isForwardedRemote = false
@@ -149,7 +162,18 @@ export function getReadRejectionStatus(req, ctx = null) {
149
162
  }
150
163
  }
151
164
 
152
- // 3. Authoritative DSH connection service check (#257)
165
+ // 3. Genuine loopback / in-process callers are admitted (#2, #271)
166
+ // Direct loopback traffic (127.0.0.1 / ::1 / localhost) not forwarded from a remote proxy
167
+ // cannot originate from the external network. In-process callers, CLI commands, and
168
+ // adjacent DSH plugins do not carry browser session cookies.
169
+ const rawRemote = req?.socket?.remoteAddress || req?.connection?.remoteAddress || ''
170
+ const cleanRemote = String(rawRemote).trim().toLowerCase().replace(/^::ffff:/, '')
171
+
172
+ if (cleanRemote && isLoopbackIp(cleanRemote) && !isForwardedRemote) {
173
+ return undefined
174
+ }
175
+
176
+ // 4. Authoritative DSH connection service check (#257)
153
177
  const conn = getConnection(ctx) || req?.connectionService || ctx?.connection
154
178
  if (conn && typeof conn.requestRejection === 'function') {
155
179
  let rejection
@@ -167,10 +191,7 @@ export function getReadRejectionStatus(req, ctx = null) {
167
191
  return undefined
168
192
  }
169
193
 
170
- // 4. Network boundary evaluation when connection service is absent
171
- const rawRemote = req?.socket?.remoteAddress || req?.connection?.remoteAddress || ''
172
- const cleanRemote = String(rawRemote).trim().toLowerCase().replace(/^::ffff:/, '')
173
-
194
+ // 5. Network boundary evaluation when connection service is absent
174
195
  if (cleanRemote && !isLoopbackIp(cleanRemote)) {
175
196
  return 401
176
197
  }
@@ -179,7 +200,6 @@ export function getReadRejectionStatus(req, ctx = null) {
179
200
  return 401
180
201
  }
181
202
 
182
- const host = String(req.headers.host || '').trim().toLowerCase()
183
203
  if (!cleanRemote && host) {
184
204
  const hostName = host.split(':')[0]
185
205
  if (!isLoopbackIp(hostName)) {
package/lib/index.js CHANGED
@@ -324,6 +324,7 @@ export function apply(ctx, config) {
324
324
  }, 'dsh-moa: llm stream interceptor')
325
325
  }
326
326
 
327
+ export { runMoAPipeline } from './moa-runner.js'
327
328
  export { executeTestGateForCandidates, runCandidateTestGate } from './moa-test-gate.js'
328
329
  export {
329
330
  COMPANION_PLUGINS,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-moa",
3
- "version": "0.2.59",
3
+ "version": "0.2.60",
4
4
  "description": "Mixture of Agents (MoA) plugin for DeepSeek Harness with /moa slash command",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",