@produtype/core 0.95.0 → 0.97.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.
|
@@ -72,9 +72,44 @@ async function detectBackend(ctx) {
|
|
|
72
72
|
* has to be a real part of what is written here before it names the backend.
|
|
73
73
|
*/
|
|
74
74
|
const goShare = (0, languageShare_1.languageShare)(ctx, /\.go$/);
|
|
75
|
-
|
|
75
|
+
/**
|
|
76
|
+
* A Go module is not a server for being a Go module.
|
|
77
|
+
*
|
|
78
|
+
* The fallback asked for a `go.mod` and enough Go to be the product, and named the
|
|
79
|
+
* backend `go`. testify is 100% Go and is a testing library: it came out with a
|
|
80
|
+
* backend, which made it a product with a server, which kept it out of the
|
|
81
|
+
* `library` profile — the same chain the `.csproj` fallback produced for Moq.
|
|
82
|
+
*
|
|
83
|
+
* Go's standard library does have an HTTP server, which is why this fallback exists
|
|
84
|
+
* at all and why Rust's was deleted in 0.71.0. So the test is the server side of
|
|
85
|
+
* it: `ListenAndServe`, an `http.Server` value, a handler registered on a mux.
|
|
86
|
+
* `net/http` alone is not enough — testify imports it to build a round tripper,
|
|
87
|
+
* which is the client.
|
|
88
|
+
*/
|
|
89
|
+
const servesOverHttp = goShare >= languageShare_1.MINIMUM_LANGUAGE_SHARE
|
|
90
|
+
? await (0, textSearch_1.searchInFiles)(ctx.root, ctx.files.source.filter((f) => /\.go$/.test(f)), [
|
|
91
|
+
/\bhttp\.ListenAndServe(TLS)?\s*\(/,
|
|
92
|
+
/\bhttp\.Server\s*\{/,
|
|
93
|
+
/\bhttp\.(Handle|HandleFunc)\s*\(/,
|
|
94
|
+
/\bhttp\.NewServeMux\s*\(/,
|
|
95
|
+
/**
|
|
96
|
+
* The handler signature, which is the contract itself.
|
|
97
|
+
*
|
|
98
|
+
* A Go service often keeps its handlers in one package and its
|
|
99
|
+
* `ListenAndServe` in another, so requiring the server call missed the
|
|
100
|
+
* commonest shape: the `password-recovery-wording` fixture is one handler
|
|
101
|
+
* taking `http.ResponseWriter` and nothing else, and it stopped being a
|
|
102
|
+
* backend. Nothing on the client side is handed a ResponseWriter — testify
|
|
103
|
+
* defines a `TestResponseWriter` of its own and never names the interface.
|
|
104
|
+
*/
|
|
105
|
+
/\bhttp\.ResponseWriter\b/,
|
|
106
|
+
], 3)
|
|
107
|
+
: [];
|
|
108
|
+
if (!namedGoFramework && servesOverHttp.length > 0 && ctx.files.all.some((f) => /(^|\/)go\.mod$/.test(f))) {
|
|
76
109
|
frameworks.push('go');
|
|
77
|
-
|
|
110
|
+
for (const hit of servesOverHttp.slice(0, 1)) {
|
|
111
|
+
evidence.push({ type: 'snippet', value: hit.snippet, file: hit.file, line: hit.line });
|
|
112
|
+
}
|
|
78
113
|
}
|
|
79
114
|
/** The JVM, read from pom.xml and build.gradle alike: coordinates are the same shape. */
|
|
80
115
|
for (const [framework, deps] of catalogue_1.JVM_BACKEND_FRAMEWORKS) {
|
|
@@ -184,7 +184,8 @@ async function detectPackaging(ctx) {
|
|
|
184
184
|
}
|
|
185
185
|
const hasManifest = ctx.packageJson !== null
|
|
186
186
|
|| all.some((f) => /(^|\/)(pyproject\.toml|setup\.py|go\.mod|Cargo\.toml|composer\.json|\w+\.gemspec)$/i.test(f))
|
|
187
|
-
|| all.some((f) => /\.(csproj|fsproj|vbproj)$/i.test(f))
|
|
187
|
+
|| all.some((f) => /\.(csproj|fsproj|vbproj|pom\.xml)$/i.test(f))
|
|
188
|
+
|| all.some((f) => /(^|\/)pom\.xml$/.test(f));
|
|
188
189
|
/**
|
|
189
190
|
* A name and a version. Without them nothing can depend on this, whatever else it
|
|
190
191
|
* does right.
|
|
@@ -227,15 +228,56 @@ async function detectPackaging(ctx) {
|
|
|
227
228
|
if (all.some((f) => f === `${crateRoot}src/lib.rs`))
|
|
228
229
|
rustCrate = true;
|
|
229
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Go says it with the absence of a `main` package.
|
|
233
|
+
*
|
|
234
|
+
* A module is importable by anything that knows its path; what makes it a program
|
|
235
|
+
* instead is a `package main`. testify is a module of 37 files with no `main`
|
|
236
|
+
* anywhere, and it came out `client-app` — below the floor, so in practice no
|
|
237
|
+
* profile at all.
|
|
238
|
+
*
|
|
239
|
+
* A repository that ships both a library and a `cmd/` binary answers no here, which
|
|
240
|
+
* is the cautious direction: a tool that also exposes packages is judged as a tool.
|
|
241
|
+
*/
|
|
242
|
+
let goLibrary = false;
|
|
243
|
+
if (all.some((f) => /(^|\/)go\.mod$/.test(f))) {
|
|
244
|
+
const goFiles = ctx.files.source.filter((f) => /\.go$/.test(f));
|
|
245
|
+
let sawMain = false;
|
|
246
|
+
for (const file of goFiles.slice(0, 80)) {
|
|
247
|
+
const raw = (await (0, readTextFileSafe_1.readTextFileSafe)(ctx.root, file)) ?? '';
|
|
248
|
+
if (/^\s*package\s+main\s*$/m.test(raw)) {
|
|
249
|
+
sawMain = true;
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
goLibrary = goFiles.length > 0 && !sawMain;
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* The JVM says it by configuring a publication.
|
|
257
|
+
*
|
|
258
|
+
* Every pom carries a groupId, an artifactId and a version, so those say nothing:
|
|
259
|
+
* an application has them too. What separates a published artifact is the plugin
|
|
260
|
+
* that uploads it — gson configures `central-publishing-maven-plugin`, Gradle
|
|
261
|
+
* projects apply `maven-publish`, older poms name a `distributionManagement`.
|
|
262
|
+
*/
|
|
263
|
+
let jvmPublication = false;
|
|
264
|
+
for (const file of all.filter((f) => /(^|\/)(pom\.xml|build\.gradle(\.kts)?)$/.test(f)).slice(0, 8)) {
|
|
265
|
+
const raw = (await (0, readTextFileSafe_1.readTextFileSafe)(ctx.root, file)) ?? '';
|
|
266
|
+
if (/maven-publish|<distributionManagement>|central-publishing-maven-plugin|maven-deploy-plugin|nexus-staging/.test(raw)) {
|
|
267
|
+
jvmPublication = true;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
230
270
|
const entrypointCount = nodeEntrypoints.length
|
|
231
271
|
+ (pythonEntrypoints ? 1 : 0)
|
|
232
272
|
+ (dotnetPackageId ? 1 : 0)
|
|
233
|
-
+ (rustCrate ? 1 : 0)
|
|
273
|
+
+ (rustCrate ? 1 : 0)
|
|
274
|
+
+ (goLibrary ? 1 : 0)
|
|
275
|
+
+ (jvmPublication ? 1 : 0);
|
|
234
276
|
return [
|
|
235
277
|
{
|
|
236
278
|
key: 'packaging.manifest',
|
|
237
279
|
present: hasManifest,
|
|
238
|
-
complete: hasManifest && (named || pythonEntrypoints || dotnetPackageId || rustCrate),
|
|
280
|
+
complete: hasManifest && (named || pythonEntrypoints || dotnetPackageId || rustCrate || goLibrary || jvmPublication),
|
|
239
281
|
evidence: hasManifest
|
|
240
282
|
? [
|
|
241
283
|
publishedMember
|
|
@@ -254,9 +296,11 @@ async function detectPackaging(ctx) {
|
|
|
254
296
|
...(pythonEntrypoints ? [{ type: 'note', value: 'a Python package or console script declaration' }] : []),
|
|
255
297
|
...(dotnetPackageId ? [{ type: 'note', value: 'a project that declares a NuGet package id' }] : []),
|
|
256
298
|
...(rustCrate ? [{ type: 'note', value: 'a Cargo package with a library crate root' }] : []),
|
|
299
|
+
...(goLibrary ? [{ type: 'note', value: 'a Go module with no main package' }] : []),
|
|
300
|
+
...(jvmPublication ? [{ type: 'note', value: 'a build that configures a Maven publication' }] : []),
|
|
257
301
|
...(hasTypes ? [{ type: 'note', value: 'TypeScript types are declared' }] : []),
|
|
258
302
|
],
|
|
259
|
-
details: { nodeEntrypoints, hasTypes, pythonEntrypoints, dotnetPackageId, rustCrate },
|
|
303
|
+
details: { nodeEntrypoints, hasTypes, pythonEntrypoints, dotnetPackageId, rustCrate, goLibrary, jvmPublication },
|
|
260
304
|
},
|
|
261
305
|
{
|
|
262
306
|
key: 'packaging.license',
|
|
@@ -195,6 +195,21 @@ async function detectSecurity(ctx) {
|
|
|
195
195
|
/^\s*SECURE_REFERRER_POLICY\s*=/m,
|
|
196
196
|
/^\s*SECURE_CROSS_ORIGIN_OPENER_POLICY\s*=/m,
|
|
197
197
|
/^\s*CSP_DEFAULT_SRC\s*=/m,
|
|
198
|
+
/**
|
|
199
|
+
* Rails writes its header policy as Ruby, not as a header name.
|
|
200
|
+
*
|
|
201
|
+
* `config.content_security_policy do |policy|` in an initializer is the policy
|
|
202
|
+
* itself, and `config.force_ssl = true` is what turns on Strict-Transport-Security
|
|
203
|
+
* for the whole application. lobsters has both and was told at `high` to add
|
|
204
|
+
* security headers.
|
|
205
|
+
*
|
|
206
|
+
* Both are lines somebody chose to write. Rails' *default* headers —
|
|
207
|
+
* `X-Frame-Options: SAMEORIGIN`, nosniff, and the rest of `DefaultHeaders` —
|
|
208
|
+
* are not counted, for the reason Django's `SecurityMiddleware` is not: every
|
|
209
|
+
* application has them, so they distinguish nothing.
|
|
210
|
+
*/
|
|
211
|
+
/config\.content_security_policy\b/,
|
|
212
|
+
/^\s*config\.force_ssl\s*=\s*true/m,
|
|
198
213
|
], 20);
|
|
199
214
|
/**
|
|
200
215
|
* Spring Security, which writes the headers without being asked.
|
|
@@ -256,7 +271,15 @@ async function detectSecurity(ctx) {
|
|
|
256
271
|
(0, detectContext_1.hasDep)(ctx, 'rate-limiter-flexible') ||
|
|
257
272
|
(0, detectContext_1.hasDep)(ctx, 'next-rate-limit') ||
|
|
258
273
|
(0, detectContext_1.hasAnyPyDep)(ctx, ['django-ratelimit', 'slowapi', 'flask-limiter']).length > 0 ||
|
|
259
|
-
(0, detectContext_1.hasAnyRustDep)(ctx, ['governor', 'tower_governor', 'tower-governor', 'actix-governor', 'ratelimit']).length > 0
|
|
274
|
+
(0, detectContext_1.hasAnyRustDep)(ctx, ['governor', 'tower_governor', 'tower-governor', 'actix-governor', 'ratelimit']).length > 0 ||
|
|
275
|
+
/**
|
|
276
|
+
* Ruby's, which is one gem and nearly universal in Rails.
|
|
277
|
+
*
|
|
278
|
+
* lobsters declares `gem "rack-attack" # rate-limiting` and was told at `high`
|
|
279
|
+
* that it does not throttle. The list had grown npm, Python and Rust entries and
|
|
280
|
+
* skipped the ecosystem where the answer is a single well-known name.
|
|
281
|
+
*/
|
|
282
|
+
(0, detectContext_1.hasAnyRubyDep)(ctx, ['rack-attack', 'rack_attack']).length > 0;
|
|
260
283
|
/**
|
|
261
284
|
* Throttling by what the protocol says, not by what the variable is called.
|
|
262
285
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@produtype/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.97.0",
|
|
4
4
|
"description": "Deterministic CLI and library that analyzes a web application repository and reports how far it is from production-ready for the kind of product it is meant to be.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|