@sap/cds 6.8.3 → 7.0.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/CHANGELOG.md +61 -2
- package/README.md +0 -1
- package/bin/cds-serve.js +50 -3
- package/bin/deploy/to-hana.js +1 -0
- package/bin/serve.js +16 -20
- package/lib/auth/basic-auth.js +6 -4
- package/lib/auth/index.js +4 -3
- package/lib/auth/jwt-auth.js +2 -5
- package/lib/compile/cds-compile.js +34 -89
- package/lib/compile/cdsc.js +11 -0
- package/lib/compile/etc/properties.js +2 -2
- package/lib/compile/for/lean_drafts.js +36 -69
- package/lib/compile/for/nodejs.js +2 -1
- package/lib/compile/load.js +1 -1
- package/lib/compile/minify.js +2 -0
- package/lib/compile/to/csn.js +74 -0
- package/{bin/build/provider/hana/2tabledata.js → lib/compile/to/hdbtabledata.js} +4 -6
- package/lib/compile/to/json.js +1 -1
- package/lib/compile/to/sql.js +8 -6
- package/lib/dbs/cds-deploy.js +174 -114
- package/lib/env/cds-env.js +64 -79
- package/lib/env/cds-requires.js +11 -28
- package/lib/env/defaults.js +13 -3
- package/lib/env/plugins.js +1 -12
- package/lib/env/presets.js +25 -21
- package/lib/index.js +121 -147
- package/lib/{core/reflect.js → linked/models.js} +2 -2
- package/lib/{core/infer.js → linked/queries.js} +2 -0
- package/lib/{core/index.js → linked/types.js} +2 -1
- package/lib/log/cds-error.js +13 -7
- package/lib/log/format/cf.js +1 -1
- package/lib/plugins.js +49 -0
- package/lib/ql/Query.js +0 -9
- package/lib/ql/STREAM.js +0 -1
- package/lib/req/context.js +2 -7
- package/lib/req/request.js +6 -2
- package/lib/req/response.js +23 -10
- package/lib/srv/middlewares/ctx-model.js +1 -1
- package/lib/srv/middlewares/errors.js +1 -1
- package/lib/srv/protocols/_legacy.js +1 -0
- package/lib/srv/protocols/graphql.js +7 -16
- package/lib/srv/protocols/index.js +59 -45
- package/lib/srv/protocols/odata-v2-proxy.js +2 -70
- package/lib/srv/srv-api.js +9 -3
- package/lib/srv/srv-dispatch.js +12 -9
- package/lib/srv/srv-models.js +4 -21
- package/lib/srv/srv-tx.js +15 -12
- package/lib/utils/cds-test.js +14 -9
- package/lib/utils/cds-utils.js +2 -12
- package/lib/utils/check-version.js +17 -0
- package/{bin/build → lib/utils}/csv-reader.js +23 -24
- package/libx/_runtime/auth/index.js +27 -23
- package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +15 -72
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +0 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +33 -63
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +14 -18
- package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +15 -5
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +5 -4
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +37 -40
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +7 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +101 -38
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/errors/AbstractError.js +5 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +2 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +9 -8
- package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +15 -11
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +4 -0
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +5 -2
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +1 -123
- package/libx/_runtime/cds-services/services/Service.js +79 -107
- package/libx/_runtime/cds-services/services/utils/columns.js +23 -19
- package/libx/_runtime/cds-services/services/utils/compareJson.js +11 -1
- package/libx/_runtime/cds-services/services/utils/differ.js +7 -2
- package/libx/_runtime/cds-services/util/assert.js +65 -2
- package/libx/_runtime/common/composition/data.js +1 -0
- package/libx/_runtime/common/generic/auth/expand.js +1 -1
- package/libx/_runtime/common/generic/auth/restrict.js +5 -10
- package/libx/_runtime/common/generic/auth/restrictions.js +40 -0
- package/libx/_runtime/common/generic/auth/utils.js +1 -2
- package/libx/_runtime/common/generic/crud.js +32 -16
- package/libx/_runtime/common/generic/etag.js +133 -104
- package/libx/_runtime/common/generic/input.js +6 -21
- package/libx/_runtime/common/generic/put.js +1 -1
- package/libx/_runtime/common/generic/stream.js +52 -0
- package/libx/_runtime/common/generic/temporal.js +25 -8
- package/libx/_runtime/common/i18n/messages.properties +0 -2
- package/libx/_runtime/common/utils/cqn.js +1 -1
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +5 -2
- package/libx/_runtime/common/utils/csn.js +0 -51
- package/libx/_runtime/common/utils/etag.js +30 -0
- package/libx/_runtime/common/utils/keys.js +1 -1
- package/libx/_runtime/common/utils/normalizeTimestamp.js +25 -0
- package/libx/_runtime/common/utils/path.js +1 -1
- package/libx/_runtime/common/utils/resolveView.js +2 -1
- package/libx/_runtime/common/utils/rewriteAsterisks.js +6 -4
- package/libx/_runtime/common/utils/search2cqn4sql.js +12 -16
- package/libx/_runtime/common/utils/stream.js +140 -0
- package/libx/_runtime/common/utils/streamProp.js +29 -12
- package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +0 -2
- package/libx/_runtime/db/generic/index.js +0 -2
- package/libx/_runtime/db/query/delete.js +2 -2
- package/libx/_runtime/db/query/insert.js +2 -2
- package/libx/_runtime/db/query/read.js +2 -2
- package/libx/_runtime/db/query/run.js +2 -2
- package/libx/_runtime/db/query/update.js +2 -2
- package/libx/_runtime/db/sql-builder/BaseBuilder.js +0 -6
- package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +23 -12
- package/libx/_runtime/db/sql-builder/FunctionBuilder.js +18 -6
- package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -0
- package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -7
- package/libx/_runtime/db/sql-builder/UpsertBuilder.js +1 -0
- package/libx/_runtime/db/utils/normalizeTimeData.js +7 -3
- package/libx/_runtime/fiori/draft.js +2 -0
- package/libx/_runtime/fiori/generic/activate.js +8 -9
- package/libx/_runtime/fiori/generic/before.js +30 -20
- package/libx/_runtime/fiori/generic/cancel.js +5 -3
- package/libx/_runtime/fiori/generic/delete.js +5 -3
- package/libx/_runtime/fiori/generic/edit.js +7 -7
- package/libx/_runtime/fiori/generic/index.js +10 -16
- package/libx/_runtime/fiori/generic/new.js +5 -3
- package/libx/_runtime/fiori/generic/patch.js +11 -8
- package/libx/_runtime/fiori/generic/prepare.js +13 -6
- package/libx/_runtime/fiori/generic/read.js +12 -6
- package/libx/_runtime/fiori/lean-draft.js +207 -152
- package/libx/_runtime/fiori/utils/delete.js +10 -5
- package/libx/_runtime/fiori/utils/req.js +17 -5
- package/libx/_runtime/fiori/utils/stream.js +36 -0
- package/libx/_runtime/hana/Service.js +12 -9
- package/libx/_runtime/hana/conversion.js +10 -15
- package/libx/_runtime/hana/driver.js +2 -0
- package/libx/_runtime/hana/execute.js +28 -6
- package/libx/_runtime/hana/pool.js +36 -122
- package/libx/_runtime/hana/search2cqn4sql.js +34 -36
- package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +2 -6
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +3 -1
- package/libx/_runtime/messaging/enterprise-messaging.js +10 -58
- package/libx/_runtime/messaging/outbox/utils.js +1 -1
- package/libx/_runtime/remote/Service.js +20 -1
- package/libx/_runtime/remote/utils/client.js +3 -5
- package/libx/_runtime/sqlite/Service.js +4 -6
- package/libx/_runtime/sqlite/conversion.js +3 -13
- package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +9 -6
- package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +6 -1
- package/libx/_runtime/sqlite/execute.js +5 -16
- package/libx/odata/afterburner.js +22 -6
- package/libx/odata/grammar.pegjs +6 -1
- package/libx/odata/parser.js +1 -1
- package/libx/rest/RestAdapter.js +16 -9
- package/libx/rest/RestRequest.js +1 -1
- package/libx/rest/middleware/input.js +2 -1
- package/libx/rest/middleware/operation.js +1 -0
- package/libx/rest/middleware/parse.js +3 -2
- package/libx/rest/middleware/payload.js +9 -8
- package/libx/rest/middleware/read.js +1 -0
- package/package.json +9 -16
- package/app/fiori/preview.js +0 -270
- package/app/fiori/routes.js +0 -59
- package/bin/build/buildTaskEngine.js +0 -360
- package/bin/build/buildTaskFactory.js +0 -283
- package/bin/build/buildTaskHandler.js +0 -241
- package/bin/build/buildTaskProvider.js +0 -22
- package/bin/build/buildTaskProviderFactory.js +0 -175
- package/bin/build/cds.js +0 -5
- package/bin/build/constants.js +0 -66
- package/bin/build/index.js +0 -58
- package/bin/build/provider/buildTaskHandlerEdmx.js +0 -82
- package/bin/build/provider/buildTaskHandlerFeatureToggles.js +0 -131
- package/bin/build/provider/buildTaskHandlerInternal.js +0 -254
- package/bin/build/provider/buildTaskProviderInternal.js +0 -383
- package/bin/build/provider/fiori/index.js +0 -171
- package/bin/build/provider/hana/2migration.js +0 -179
- package/bin/build/provider/hana/index.js +0 -505
- package/bin/build/provider/hana/migrationtable.js +0 -472
- package/bin/build/provider/hana/template/.hdiconfig-haas +0 -163
- package/bin/build/provider/hana/template/.hdiconfig-hanacloud +0 -137
- package/bin/build/provider/hana/template/.hdinamespace +0 -4
- package/bin/build/provider/hana/template/package.json +0 -12
- package/bin/build/provider/hana/template/undeploy.json +0 -5
- package/bin/build/provider/java/index.js +0 -111
- package/bin/build/provider/java-cf/index.js +0 -1
- package/bin/build/provider/mtx/index.js +0 -268
- package/bin/build/provider/mtx/resourcesTarBuilder.js +0 -95
- package/bin/build/provider/mtx-extension/index.js +0 -131
- package/bin/build/provider/mtx-sidecar/index.js +0 -137
- package/bin/build/provider/node-cf/index.js +0 -1
- package/bin/build/provider/nodejs/index.js +0 -192
- package/bin/build/util.js +0 -299
- package/bin/cds.js +0 -125
- package/bin/deploy/to-hana/cfUtil.js +0 -355
- package/bin/deploy/to-hana/gitUtil.js +0 -57
- package/bin/deploy/to-hana/hana.js +0 -306
- package/bin/deploy/to-hana/hdiDeployUtil.js +0 -153
- package/bin/deploy/to-hana/index.js +0 -16
- package/bin/deploy/to-hana/mtaUtil.js +0 -170
- package/bin/mtx/in-cds.js +0 -17
- package/bin/plugins.js +0 -32
- package/bin/run.js +0 -24
- package/bin/utils/log.js +0 -24
- package/bin/version.js +0 -178
- package/libx/_runtime/audit/Service.js +0 -222
- package/libx/_runtime/audit/generic/personal/access.js +0 -61
- package/libx/_runtime/audit/generic/personal/index.js +0 -56
- package/libx/_runtime/audit/generic/personal/modification.js +0 -132
- package/libx/_runtime/audit/generic/personal/utils.js +0 -186
- package/libx/_runtime/audit/utils/log.js +0 -23
- package/libx/_runtime/audit/utils/v2.js +0 -176
- package/libx/_runtime/db/data-conversion/timestamp.js +0 -9
- package/libx/_runtime/db/generic/integrity.js +0 -455
- package/srv/audit-log.cds +0 -87
- package/srv/mtx.cds +0 -2
- package/srv/mtx.js +0 -8
- /package/lib/{core → linked}/classes.js +0 -0
- /package/lib/{core → linked}/entities.js +0 -0
package/bin/run.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
const serve = require ('./serve')
|
|
2
|
-
module.exports = Object.assign (
|
|
3
|
-
cds_run, serve, {help: `
|
|
4
|
-
# SYNOPSIS
|
|
5
|
-
|
|
6
|
-
*cds run* [<project>] [<options>]
|
|
7
|
-
|
|
8
|
-
Runs 'cds serve all' for the specified project, with default <project> = cwd.
|
|
9
|
-
|
|
10
|
-
# OPTIONS
|
|
11
|
-
|
|
12
|
-
- see _cds help serve_
|
|
13
|
-
|
|
14
|
-
# SEE ALSO
|
|
15
|
-
|
|
16
|
-
Actually, *cds run* is just a convenient shortcut for:
|
|
17
|
-
*cds serve* [--project <project>] [<options>] ...
|
|
18
|
-
Check out *cds serve --help* to learn more.
|
|
19
|
-
|
|
20
|
-
`})
|
|
21
|
-
|
|
22
|
-
function cds_run (projects, options) {
|
|
23
|
-
return serve (projects,{ project:true, ...options })
|
|
24
|
-
}
|
package/bin/utils/log.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// sorts, filters, and writes compilation messages to console
|
|
2
|
-
module.exports = (messages, options={}) => {
|
|
3
|
-
const { format } = require('./term')
|
|
4
|
-
const logLevel = options && options['log-level'] || require('../../lib').env.log.levels.cli || ''
|
|
5
|
-
const levels = {
|
|
6
|
-
debug: { Error:4, undefined:4, Warning:3, Info:2, Debug:1 },
|
|
7
|
-
info: { Error:4, undefined:4, Warning:3, Info:2 },
|
|
8
|
-
warn: { Error:4, undefined:4, Warning:3 },
|
|
9
|
-
error: { Error:4, undefined:4 },
|
|
10
|
-
} [logLevel.toLowerCase()] || { Error:4, undefined:4, Warning:3 }
|
|
11
|
-
const log = options.log || console.error
|
|
12
|
-
|
|
13
|
-
if (!Array.isArray (messages)) messages = [messages]
|
|
14
|
-
for (let m of messages.filter (m => m.severity in levels)) {
|
|
15
|
-
// show stack for resolution issues since there the requiring code location is in the stack
|
|
16
|
-
// check for standard Error classes, but not Error itself
|
|
17
|
-
const internalError = m.name === 'EvalError' || m.name === 'InternalError' || m.name === 'RangeError'
|
|
18
|
-
|| m.name === 'ReferenceError' || m.name === 'SyntaxError' || m.name === 'TypeError'
|
|
19
|
-
|| m.name === 'URIError'
|
|
20
|
-
const mf = format (m, m.severity, internalError, true)
|
|
21
|
-
log (mf)
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
/* eslint no-console:off */
|
package/bin/version.js
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
/* eslint-disable no-console */
|
|
2
|
-
const { dirname, join, resolve } = require ('path')
|
|
3
|
-
const { cwd } = require('process')
|
|
4
|
-
module.exports = Object.assign(list_versions, {
|
|
5
|
-
flags: [ '--info', '--markdown', '--all', '--npm-list', '--npm-tree', '--no-colors'],
|
|
6
|
-
shortcuts: [ '-i', '-m','-a', '-ls', '-ll' ],
|
|
7
|
-
info,
|
|
8
|
-
help: `
|
|
9
|
-
# SYNOPSIS
|
|
10
|
-
|
|
11
|
-
*cds version* <options>
|
|
12
|
-
*cds -v* <option>
|
|
13
|
-
|
|
14
|
-
Prints the versions of all @sap/cds packages in your package dependencies.
|
|
15
|
-
|
|
16
|
-
# OPTIONS
|
|
17
|
-
|
|
18
|
-
*-i | --info*
|
|
19
|
-
|
|
20
|
-
Prints version information in a tabular markdown format, which you
|
|
21
|
-
can embed into your bug reports.
|
|
22
|
-
|
|
23
|
-
*-a | --all*
|
|
24
|
-
|
|
25
|
-
Also lists sub-packages and optional dependencies.
|
|
26
|
-
|
|
27
|
-
*-ls | --npm-list* <pattern>
|
|
28
|
-
*-ll | --npm-tree* <pattern>
|
|
29
|
-
|
|
30
|
-
Prints an npm ls tree filtered to the specified pattern.
|
|
31
|
-
(default: '@sap/cds')
|
|
32
|
-
|
|
33
|
-
`})
|
|
34
|
-
|
|
35
|
-
const MISSING = '-- missing --'
|
|
36
|
-
|
|
37
|
-
function list_versions(args, options) { //NOSONAR
|
|
38
|
-
if (options['npm-list'] || options['npm-tree']) {
|
|
39
|
-
let [pattern] = args, re = pattern ? RegExp(pattern) : /@sap\/cd[rs]|@sap\/eslint-plugin-cds/
|
|
40
|
-
let cmd = 'npm ls --depth ' + (options['npm-tree'] ? 11 : 0)
|
|
41
|
-
console.log (cmd,'| grep', pattern)
|
|
42
|
-
return require('child_process').exec(cmd, (e,stdout)=>{
|
|
43
|
-
// if (e) console.error(e)
|
|
44
|
-
const replacement = (options['no-colors'] ? '$1 $2$3$4' : '\x1b[91m$1 \x1b[32m$2\x1b[0m\x1b[2m$3\x1b[32m$4\x1b[0m');
|
|
45
|
-
for (let line of stdout.split(/\n/)) if (line.match(re)) console.log(
|
|
46
|
-
line.replace(/(@sap[^@]*)@([\S]+)( -> [\S]+)?(deduped)?/,replacement)
|
|
47
|
-
)
|
|
48
|
-
})
|
|
49
|
-
}
|
|
50
|
-
const versions = info (options)
|
|
51
|
-
if (options.markdown) return _markdown (versions)
|
|
52
|
-
if (options.info) return _markdown (versions)
|
|
53
|
-
const mark = options['no-colors'] ? s => s : require('./utils/term').info
|
|
54
|
-
for (let each of Object.keys(versions).sort()) console.log(`${mark(each)}: ${versions[each]}`)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function info(o) {
|
|
58
|
-
const { npmGlobalModules } = require('./utils/modules');
|
|
59
|
-
const main = _findPackage (require.main.filename)
|
|
60
|
-
const sap_cds = require.resolve('@sap/cds/package.json', {paths:[process.cwd(), __dirname]})
|
|
61
|
-
return {
|
|
62
|
-
// REVISIT: Why do we need all these different hard-coded ways, including proliferation of arguments?
|
|
63
|
-
..._versions4(main, {}, true), // usually sap/cds-dk or sap/cds
|
|
64
|
-
..._versions4('@sap/cds-dk', {}, null, o), // make sure cds-dk is there, cds-maven-plugin uses it
|
|
65
|
-
..._versions4('@sap/cds-dk', {}, null, {...o, label: '@sap/cds-dk (global)', pkg: join(npmGlobalModules(), '@sap/cds-dk')}),
|
|
66
|
-
..._versions4('@sap/eslint-plugin-cds', {}, null, o),
|
|
67
|
-
..._versions4(process.cwd(), {}, null, o),
|
|
68
|
-
..._versions4('..', {}, null, o),
|
|
69
|
-
..._findMTX(),
|
|
70
|
-
'@sap/cds': require(sap_cds).version, // ensure effective sap/cds version is listed
|
|
71
|
-
'Node.js': process.version,
|
|
72
|
-
'home': __dirname.slice(0,-4)
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function _versions4 (pkg_name, info, parent, o={}) {
|
|
77
|
-
if (!pkg_name) return info
|
|
78
|
-
try {
|
|
79
|
-
let path = join(o.pkg || pkg_name, 'package.json')
|
|
80
|
-
if(o.here) {
|
|
81
|
-
// path.join(['./', x]) is immediately resolved to x.
|
|
82
|
-
// Calling require() on that will then follow the standard (global) module resolution strategy.
|
|
83
|
-
// If we want to look into a directory relative to CWD,
|
|
84
|
-
// turning it into a global path is the most convenient way.
|
|
85
|
-
path = join(cwd(), path)
|
|
86
|
-
}
|
|
87
|
-
const pkg = require(path)
|
|
88
|
-
info[o.label || pkg.name] = pkg.version
|
|
89
|
-
// console.log(o.label || pkg.name, pkg.version, path)
|
|
90
|
-
if (!parent || o.all) for (let d in pkg.dependencies) { // recurse sap packages in dependencies...
|
|
91
|
-
if (!(d in info) && (d.startsWith('@sap/') || d.startsWith('@cap-js/'))) _versions4(d, info, pkg.name, o)
|
|
92
|
-
}
|
|
93
|
-
} catch (e) {
|
|
94
|
-
if (e.code !== 'MODULE_NOT_FOUND') info[pkg_name] = MISSING // unknown error
|
|
95
|
-
// require fails for indirect packages if node_modules layout is nested, e.g. on Windows.
|
|
96
|
-
// Try one more time with nested node_modules dir.
|
|
97
|
-
else if (parent) _versions4(parent + '/node_modules/' + pkg_name, info)
|
|
98
|
-
}
|
|
99
|
-
return info
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
function _markdown (versions) {
|
|
104
|
-
console.log()
|
|
105
|
-
const pkg = { name:'', repository:'', version:'' }; try {
|
|
106
|
-
Object.assign (pkg, require (resolve('package.json')))
|
|
107
|
-
} catch (e) {/* ignored */}
|
|
108
|
-
console.log ('|', pkg.name, '|', pkg.repository.url || pkg.repository, '|')
|
|
109
|
-
console.log ('|:---------------------- | ----------- |')
|
|
110
|
-
if (require('../lib').env['project-nature'] === 'nodejs') {
|
|
111
|
-
console.log ('|', v('Node.js'), '|')
|
|
112
|
-
console.log ('|', v('@sap/cds'), '|')
|
|
113
|
-
} else {
|
|
114
|
-
console.log ('|', v('CAP Java Runtime'), '|')
|
|
115
|
-
console.log ('|', v('OData Version'), '|')
|
|
116
|
-
}
|
|
117
|
-
console.log ('|', v('@sap/cds-compiler'), '|')
|
|
118
|
-
console.log ('|', v('@sap/cds-dk'), '|')
|
|
119
|
-
console.log ('|', v('@sap/cds-dk (global)'), '|')
|
|
120
|
-
console.log ('|', v('@sap/eslint-plugin-cds'), '|')
|
|
121
|
-
function v (component) {
|
|
122
|
-
const version = versions [component] || '_version_'
|
|
123
|
-
return (component + ' ').slice(0,22)
|
|
124
|
-
+' | '+ (version + ' ').slice(0,11)
|
|
125
|
-
}
|
|
126
|
-
console.log()
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function _findPackage (dir) {
|
|
130
|
-
try {
|
|
131
|
-
if (dir) {
|
|
132
|
-
require.resolve(join (dir, 'package.json'))
|
|
133
|
-
return dir
|
|
134
|
-
}
|
|
135
|
-
} catch (e) {
|
|
136
|
-
if (e.code !== 'MODULE_NOT_FOUND') throw e
|
|
137
|
-
return _findPackage (dirname (dir))
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function _findMTX() {
|
|
142
|
-
// looks for any occurrence of cds-mtx.
|
|
143
|
-
// In node projects, cds-mtx can be resolved via _versions4 like all the other SAP modules
|
|
144
|
-
// In Java-flavoured projects cds-mtx may be deployed through a separate node project
|
|
145
|
-
// with just sidecar in it. So we can not rely on the global require() resolution strategy
|
|
146
|
-
// and will as a fallback...
|
|
147
|
-
// (1) ...look for an MTX project within cds.env
|
|
148
|
-
// (2) ...look within a few preselected subdirectories which often contain MTX projects
|
|
149
|
-
const cds = require('../lib')
|
|
150
|
-
const cdsmtx = '@sap/cds-mtx'
|
|
151
|
-
let res = _versions4 (cdsmtx, {}, null)
|
|
152
|
-
|
|
153
|
-
if (res[cdsmtx] === undefined) {
|
|
154
|
-
// not resolvable -> look in cds.env
|
|
155
|
-
if ('build' in cds.env && 'tasks' in cds.env.build) {
|
|
156
|
-
let i = 0
|
|
157
|
-
while (res[cdsmtx] === undefined && i < cds.env.build.tasks.length) {
|
|
158
|
-
const task = cds.env.build.tasks[i]
|
|
159
|
-
if ('for' in task && task.for === 'mtx' && 'dest' in task) {
|
|
160
|
-
res = _versions4 (join(task.dest, 'node_modules', cdsmtx), {}, null, {here: true})
|
|
161
|
-
}
|
|
162
|
-
i++
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// mtx still not found via cds.env? Try looking in well-known subdirectories
|
|
167
|
-
const folders = cds.env.folders
|
|
168
|
-
? [cds.env.folders.db, cds.env.folders.srv].flat().filter(d => d)
|
|
169
|
-
: []
|
|
170
|
-
let i = 0
|
|
171
|
-
while(res[cdsmtx] === undefined && i < folders.length) {
|
|
172
|
-
res = _versions4 (join(folders[i], 'node_modules', cdsmtx), {}, null, {here: true})
|
|
173
|
-
i++
|
|
174
|
-
}
|
|
175
|
-
res[cdsmtx] = res[cdsmtx] || MISSING
|
|
176
|
-
}
|
|
177
|
-
return res
|
|
178
|
-
}
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
const cds = require('../cds')
|
|
2
|
-
const OutboxService = require('../messaging/Outbox')
|
|
3
|
-
const {
|
|
4
|
-
connect,
|
|
5
|
-
buildDataAccessLogs,
|
|
6
|
-
sendDataAccessLog,
|
|
7
|
-
buildDataModificationLogs,
|
|
8
|
-
sendDataModificationLog,
|
|
9
|
-
buildSecurityLog,
|
|
10
|
-
sendSecurityLog,
|
|
11
|
-
buildConfigChangeLogs,
|
|
12
|
-
sendConfigChangeLog
|
|
13
|
-
} = require('./utils/v2')
|
|
14
|
-
const ANONYMOUS = 'anonymous'
|
|
15
|
-
const PLAN = {
|
|
16
|
-
standard: 'standard',
|
|
17
|
-
OAuth2: 'OAuth2'
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const _getTenantAndUser = options => {
|
|
21
|
-
// REVISIT: the standard plan is deprecated/insecure
|
|
22
|
-
if (options.plan === PLAN.standard) {
|
|
23
|
-
return {
|
|
24
|
-
user: cds.context?.user?.id ?? ANONYMOUS,
|
|
25
|
-
tenant: cds.context?.tenant
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return {
|
|
30
|
-
user: '$USER',
|
|
31
|
-
tenant: '$PROVIDER'
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const _getSecurityContext = () => {
|
|
36
|
-
const securityContext = cds?.context?.http?.req?.authInfo
|
|
37
|
-
|
|
38
|
-
if (!securityContext) {
|
|
39
|
-
const errorMsg =
|
|
40
|
-
'[Audit Logging]: The Programmatic API of the Audit Logging service for the OAuth2 plan (API - V2) can only be ' +
|
|
41
|
-
'called within the context of a request event handler. The authInfo property of the request interface (req.authInfo) ' +
|
|
42
|
-
"is used to get the security context required for the implementation's proper functioning."
|
|
43
|
-
throw new Error(errorMsg)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return securityContext
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
module.exports = class AuditLogService extends OutboxService {
|
|
50
|
-
async init() {
|
|
51
|
-
// call OutboxService's init, which handles outboxing
|
|
52
|
-
await super.init()
|
|
53
|
-
|
|
54
|
-
const credentials = this.options.credentials
|
|
55
|
-
this.options.plan = !credentials || !credentials.uaa ? PLAN.standard : PLAN.OAuth2
|
|
56
|
-
|
|
57
|
-
// REVISIT: the standard plan is deprecated/insecure
|
|
58
|
-
if (this.options.plan === PLAN.standard) {
|
|
59
|
-
const auditLogClient = await connect(credentials)
|
|
60
|
-
if (auditLogClient) this.#registerOnHandlers(auditLogClient)
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// OAuth2 plan
|
|
65
|
-
const outbox = cds.requires['audit-log'].outbox
|
|
66
|
-
if (outbox?.kind === 'persistent-outbox' || (outbox && cds.requires.outbox?.kind === 'persistent-outbox')) {
|
|
67
|
-
throw new Error('The OAuth2 plan is not currently supported with persistent outbox')
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (credentials?.uaa) this.#registerOnHandlers()
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async emit(first, second) {
|
|
74
|
-
const { event, data } = typeof first === 'object' ? first : { event: first, data: second }
|
|
75
|
-
if (!this.options.outbox) return this.send(event, data)
|
|
76
|
-
|
|
77
|
-
if (this[event]) {
|
|
78
|
-
try {
|
|
79
|
-
// this will open a new tx -> preserve user
|
|
80
|
-
await super.send(new cds.Request({ method: event, data, user: cds.context.user }))
|
|
81
|
-
} catch (e) {
|
|
82
|
-
if (e.code === 'ERR_ASSERTION') {
|
|
83
|
-
e.unrecoverable = true
|
|
84
|
-
}
|
|
85
|
-
throw e
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async send(event, data) {
|
|
91
|
-
if (this[event]) return super.send(event, data)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/*
|
|
95
|
-
* api (await AuditLogService.<event>(data))
|
|
96
|
-
*/
|
|
97
|
-
|
|
98
|
-
async dataAccessLog(data) {
|
|
99
|
-
return super.send('dataAccessLog', data)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async dataModificationLog(data) {
|
|
103
|
-
return super.send('dataModificationLog', data)
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async securityLog(data) {
|
|
107
|
-
return super.send('securityLog', data)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async configChangeLog(data) {
|
|
111
|
-
return super.send('configChangeLog', data)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/*
|
|
115
|
-
* impl
|
|
116
|
-
*/
|
|
117
|
-
|
|
118
|
-
#registerOnHandlers(auditLogClient) {
|
|
119
|
-
this.on('dataAccessLog', function (req) {
|
|
120
|
-
return this._dataAccessLog(req, auditLogClient)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
this.on('dataModificationLog', function (req) {
|
|
124
|
-
return this._dataModificationLog(req, auditLogClient)
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
this.on('securityLog', function (req) {
|
|
128
|
-
return this._securityLog(req, auditLogClient)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
this.on('configChangeLog', function (req) {
|
|
132
|
-
return this._configChangeLog(req, auditLogClient)
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async _dataAccessLog({ data: { accesses } }, auditLogClient) {
|
|
137
|
-
const { tenant, user } = _getTenantAndUser(this.options)
|
|
138
|
-
|
|
139
|
-
// build the logs
|
|
140
|
-
auditLogClient = auditLogClient ?? (await connect(this.options.credentials, _getSecurityContext()))
|
|
141
|
-
const { entries, errors } = buildDataAccessLogs(auditLogClient, accesses, tenant, user)
|
|
142
|
-
if (errors.length) {
|
|
143
|
-
throw errors.length === 1 ? errors[0] : Object.assign(new Error('MULTIPLE_ERRORS'), { details: errors })
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// write the logs
|
|
147
|
-
await Promise.all(entries.map(entry => sendDataAccessLog(entry).catch(err => errors.push(err))))
|
|
148
|
-
|
|
149
|
-
if (errors.length) {
|
|
150
|
-
throw errors.length === 1 ? errors[0] : Object.assign(new Error('MULTIPLE_ERRORS'), { details: errors })
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// REVISIT: modification.action not used in auditlog v2
|
|
155
|
-
async _dataModificationLog({ data: { modifications } }, auditLogClient) {
|
|
156
|
-
const { tenant, user } = _getTenantAndUser(this.options)
|
|
157
|
-
|
|
158
|
-
// build the logs
|
|
159
|
-
auditLogClient = auditLogClient ?? (await connect(this.options.credentials, _getSecurityContext()))
|
|
160
|
-
const { entries, errors } = buildDataModificationLogs(auditLogClient, modifications, tenant, user)
|
|
161
|
-
if (errors.length) {
|
|
162
|
-
throw errors.length === 1 ? errors[0] : Object.assign(new Error('MULTIPLE_ERRORS'), { details: errors })
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// write the logs
|
|
166
|
-
await Promise.all(entries.map(entry => sendDataModificationLog(entry).catch(err => errors.push(err))))
|
|
167
|
-
|
|
168
|
-
if (errors.length) {
|
|
169
|
-
throw errors.length === 1 ? errors[0] : Object.assign(new Error('MULTIPLE_ERRORS'), { details: errors })
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
async _securityLog({ data: { action, data } }, auditLogClient) {
|
|
174
|
-
let { tenant, user } = _getTenantAndUser(this.options)
|
|
175
|
-
|
|
176
|
-
// cds.context may not be proper on auth-related errors -> try to extract from data
|
|
177
|
-
if (!tenant && user === ANONYMOUS) {
|
|
178
|
-
try {
|
|
179
|
-
const parsed = JSON.parse(data)
|
|
180
|
-
if (parsed.tenant) {
|
|
181
|
-
tenant = parsed.tenant
|
|
182
|
-
delete parsed.tenant
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (parsed.user && typeof parsed.user === 'string') {
|
|
186
|
-
user = parsed.user
|
|
187
|
-
delete parsed.user
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
data = JSON.stringify(parsed)
|
|
191
|
-
} catch (e) {
|
|
192
|
-
// ignore
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// build the log
|
|
197
|
-
auditLogClient = auditLogClient ?? (await connect(this.options.credentials, _getSecurityContext()))
|
|
198
|
-
const entry = buildSecurityLog(auditLogClient, action, data, tenant, user)
|
|
199
|
-
|
|
200
|
-
// write the log
|
|
201
|
-
await sendSecurityLog(entry)
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// REVISIT: action and success not used in auditlog v2
|
|
205
|
-
async _configChangeLog({ data: { configurations } }, auditLogClient) {
|
|
206
|
-
const { tenant, user } = _getTenantAndUser(this.options)
|
|
207
|
-
|
|
208
|
-
// build the logs
|
|
209
|
-
auditLogClient = auditLogClient ?? (await connect(this.options.credentials, _getSecurityContext()))
|
|
210
|
-
const { entries, errors } = buildConfigChangeLogs(auditLogClient, configurations, tenant, user)
|
|
211
|
-
if (errors.length) {
|
|
212
|
-
throw errors.length === 1 ? errors[0] : Object.assign(new Error('MULTIPLE_ERRORS'), { details: errors })
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// write the logs
|
|
216
|
-
await Promise.all(entries.map(entry => sendConfigChangeLog(entry).catch(err => errors.push(err))))
|
|
217
|
-
|
|
218
|
-
if (errors.length) {
|
|
219
|
-
throw errors.length === 1 ? errors[0] : Object.assign(new Error('MULTIPLE_ERRORS'), { details: errors })
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
const cds = require('../../../cds')
|
|
2
|
-
|
|
3
|
-
const getTemplate = require('../../../common/utils/template')
|
|
4
|
-
const templateProcessor = require('../../../common/utils/templateProcessor')
|
|
5
|
-
|
|
6
|
-
const {
|
|
7
|
-
getRootEntity,
|
|
8
|
-
getPick,
|
|
9
|
-
createLogEntry,
|
|
10
|
-
addObjectID,
|
|
11
|
-
addDataSubject,
|
|
12
|
-
addDataSubjectForDetailsEntity,
|
|
13
|
-
resolveDataSubjectPromises
|
|
14
|
-
} = require('./utils')
|
|
15
|
-
|
|
16
|
-
const _processorFnAccess = (accessLogs, model, req) => {
|
|
17
|
-
return ({ row, key, element, plain }) => {
|
|
18
|
-
if (row.IsActiveEntity === false) return
|
|
19
|
-
|
|
20
|
-
const entity = getRootEntity(element)
|
|
21
|
-
|
|
22
|
-
// create or augment log entry
|
|
23
|
-
const entry = createLogEntry(accessLogs, entity, row)
|
|
24
|
-
|
|
25
|
-
// process categories
|
|
26
|
-
for (const category of plain.categories) {
|
|
27
|
-
if (category === 'ObjectID') addObjectID(entry, row, key)
|
|
28
|
-
else if (category === 'DataSubjectID') addDataSubject(entry, row, key, entity)
|
|
29
|
-
else if (category === 'IsPotentiallySensitive' && key in row) {
|
|
30
|
-
if (!entry.attributes.some(e => e.name === key)) entry.attributes.push({ name: key })
|
|
31
|
-
// REVISIT: attribute vs. attachment?
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// add promise to determine data subject if a DataSubjectDetails entity
|
|
36
|
-
const semantics = entity['@PersonalData.EntitySemantics']
|
|
37
|
-
if (
|
|
38
|
-
(semantics === 'DataSubjectDetails' || semantics === 'Other') &&
|
|
39
|
-
entry.dataSubject.id.length === 0 // > id still an array -> promise not yet set
|
|
40
|
-
) {
|
|
41
|
-
addDataSubjectForDetailsEntity(row, entry, req, entity, model)
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const auditAccessHandler = async function (data, req) {
|
|
47
|
-
const auditLogService = await cds.connect.to('audit-log')
|
|
48
|
-
const mock = Object.assign({ name: req.target._service.name, model: this.model })
|
|
49
|
-
const template = getTemplate('personal_read', mock, req.target, { pick: getPick('READ') })
|
|
50
|
-
if (!template.elements.size) return
|
|
51
|
-
const accessLogs = {}
|
|
52
|
-
if (typeof data === 'object' && data !== null) {
|
|
53
|
-
const processFn = _processorFnAccess(accessLogs, this.model, req)
|
|
54
|
-
const data_ = Array.isArray(data) ? data : [data]
|
|
55
|
-
data_.forEach(row => templateProcessor({ processFn, row, template }))
|
|
56
|
-
const accesses = (await resolveDataSubjectPromises(accessLogs)).filter(ele => ele.attributes.length)
|
|
57
|
-
if (accesses.length) await auditLogService.emit('dataAccessLog', { accesses })
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
module.exports = { auditAccessHandler }
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
const cds = require('../../../cds')
|
|
2
|
-
const {
|
|
3
|
-
attachDiffToContextHandler,
|
|
4
|
-
calcModificationLogsHandler4Before,
|
|
5
|
-
calcModificationLogsHandler4After,
|
|
6
|
-
emitModificationHandler
|
|
7
|
-
} = require('./modification')
|
|
8
|
-
const { auditAccessHandler } = require('./access')
|
|
9
|
-
|
|
10
|
-
exports.impl = cds.service.impl(function () {
|
|
11
|
-
if (!cds.db) return cds.on('connect', srv => srv.isDatabaseService && exports.impl.call(this))
|
|
12
|
-
// REVISIT: diff() doesn't work in srv after phase but foreign key propagation has not yet taken place in srv before phase
|
|
13
|
-
// -> calc diff in db layer and store in audit data structure at context
|
|
14
|
-
// -> REVISIT for GA: clear req._.partialPersistentState?
|
|
15
|
-
attachDiffToContextHandler._initial = true
|
|
16
|
-
for (const e of this.entities) {
|
|
17
|
-
if (!_hasPersonalData(e)) continue
|
|
18
|
-
|
|
19
|
-
if (e['@AuditLog.Operation.Insert']) {
|
|
20
|
-
cds.db.before('CREATE', e, attachDiffToContextHandler)
|
|
21
|
-
// create -> all new -> calcModificationLogsHandler in after phase
|
|
22
|
-
cds.db.after('CREATE', e, calcModificationLogsHandler4After)
|
|
23
|
-
this.after('CREATE', e, emitModificationHandler)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (e['@AuditLog.Operation.Update']) {
|
|
27
|
-
cds.db.before('UPDATE', e, attachDiffToContextHandler)
|
|
28
|
-
// update -> mixed (via deep) -> calcModificationLogsHandler in before and after phase
|
|
29
|
-
cds.db.before('UPDATE', e, calcModificationLogsHandler4Before)
|
|
30
|
-
cds.db.after('UPDATE', e, calcModificationLogsHandler4After)
|
|
31
|
-
this.after('UPDATE', e, emitModificationHandler)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
if (e['@AuditLog.Operation.Delete']) {
|
|
35
|
-
cds.db.before('DELETE', e, attachDiffToContextHandler)
|
|
36
|
-
// delete -> all done -> calcModificationLogsHandler in before phase
|
|
37
|
-
cds.db.before('DELETE', e, calcModificationLogsHandler4Before)
|
|
38
|
-
this.after('DELETE', e, emitModificationHandler)
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (e['@AuditLog.Operation.Read']) {
|
|
42
|
-
this.after('READ', e, auditAccessHandler)
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
const _hasPersonalData = e => {
|
|
48
|
-
if (!e['@PersonalData.DataSubjectRole']) return
|
|
49
|
-
if (!e['@PersonalData.EntitySemantics']) return
|
|
50
|
-
return !!Object.values(e.elements).some(
|
|
51
|
-
e =>
|
|
52
|
-
e['@PersonalData.IsPotentiallyPersonal'] ||
|
|
53
|
-
e['@PersonalData.IsPotentiallySensitive'] ||
|
|
54
|
-
(e['@PersonalData.FieldSemantics'] && e['@PersonalData.FieldSemantics'] === 'DataSubjectID')
|
|
55
|
-
)
|
|
56
|
-
}
|