analytics_ops 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +76 -0
- data/CONTRIBUTING.md +2 -1
- data/README.md +232 -41
- data/SECURITY.md +8 -8
- data/docs/api-support-matrix.md +9 -8
- data/docs/architecture.md +22 -4
- data/docs/authentication.md +112 -51
- data/docs/commands.md +71 -17
- data/docs/configuration-schema-v1.json +53 -7
- data/docs/configuration.md +33 -9
- data/docs/google-client-compatibility.md +10 -6
- data/docs/live-smoke-test.md +159 -0
- data/docs/plan-format.md +4 -0
- data/docs/plan-schema-v1.json +113 -22
- data/docs/rails.md +12 -3
- data/docs/reports.md +44 -6
- data/docs/safety.md +18 -6
- data/docs/troubleshooting.md +42 -13
- data/lib/analytics_ops/applier.rb +2 -1
- data/lib/analytics_ops/cli/options.rb +157 -0
- data/lib/analytics_ops/cli/presenter.rb +221 -0
- data/lib/analytics_ops/cli.rb +172 -201
- data/lib/analytics_ops/clients/admin.rb +130 -129
- data/lib/analytics_ops/clients/admin_normalization.rb +95 -0
- data/lib/analytics_ops/clients/data.rb +120 -63
- data/lib/analytics_ops/clients/error_translation.rb +45 -0
- data/lib/analytics_ops/configuration/document.rb +1 -1
- data/lib/analytics_ops/configuration/loader.rb +38 -5
- data/lib/analytics_ops/configuration/schema.rb +51 -8
- data/lib/analytics_ops/configuration/validator.rb +43 -8
- data/lib/analytics_ops/configuration/writer.rb +105 -0
- data/lib/analytics_ops/configuration.rb +1 -0
- data/lib/analytics_ops/connection.rb +93 -0
- data/lib/analytics_ops/desired_state.rb +2 -2
- data/lib/analytics_ops/plan.rb +94 -33
- data/lib/analytics_ops/planner.rb +10 -2
- data/lib/analytics_ops/rails/railtie.rb +13 -18
- data/lib/analytics_ops/redaction.rb +14 -9
- data/lib/analytics_ops/reports/catalog.rb +22 -5
- data/lib/analytics_ops/reports/definition.rb +74 -37
- data/lib/analytics_ops/reports/overview.rb +55 -0
- data/lib/analytics_ops/reports/overview_result.rb +54 -0
- data/lib/analytics_ops/reports/result.rb +38 -9
- data/lib/analytics_ops/reports.rb +2 -0
- data/lib/analytics_ops/resources.rb +2 -1
- data/lib/analytics_ops/service_account.rb +171 -0
- data/lib/analytics_ops/setup.rb +171 -0
- data/lib/analytics_ops/snapshot.rb +20 -5
- data/lib/analytics_ops/version.rb +1 -1
- data/lib/analytics_ops/workspace.rb +41 -12
- data/lib/analytics_ops.rb +4 -0
- data/lib/generators/analytics_ops/install_generator.rb +2 -0
- data/lib/generators/analytics_ops/templates/analytics_ops.yml +2 -15
- data/sig/analytics_ops.rbs +117 -10
- metadata +26 -1
data/docs/authentication.md
CHANGED
|
@@ -1,86 +1,147 @@
|
|
|
1
1
|
# Authentication
|
|
2
2
|
|
|
3
|
-
Analytics Ops
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Analytics Ops supports one authentication method: a Google service-account
|
|
4
|
+
JSON key.
|
|
5
|
+
|
|
6
|
+
It does not use `gcloud`, browser login, Desktop OAuth, Application Default
|
|
7
|
+
Credentials, `GOOGLE_APPLICATION_CREDENTIALS`, or API keys.
|
|
8
|
+
|
|
9
|
+
## One-time setup
|
|
10
|
+
|
|
11
|
+
You need a Google Cloud project only to own the service account, enable the two
|
|
12
|
+
Analytics APIs, and supply API quota. It does not need to be the project that
|
|
13
|
+
hosts your website.
|
|
14
|
+
|
|
15
|
+
1. In the Cloud project, enable:
|
|
16
|
+
- Google Analytics Admin API
|
|
17
|
+
- Google Analytics Data API
|
|
18
|
+
2. Open [Google Cloud service accounts](https://console.cloud.google.com/iam-admin/serviceaccounts).
|
|
19
|
+
3. Create a service account named **Analytics Ops Local**. Do not grant broad
|
|
20
|
+
Cloud IAM roles.
|
|
21
|
+
4. Open the service account, choose **Keys**, create a JSON key, and save it
|
|
22
|
+
outside every source repository.
|
|
23
|
+
5. Copy the service-account email, such as
|
|
24
|
+
`analytics-ops@example-project.iam.gserviceaccount.com`.
|
|
25
|
+
6. In GA4, open **Admin → Account access management → Add users**.
|
|
26
|
+
7. Add the service-account email:
|
|
27
|
+
- **Viewer** is enough for reports, discovery, snapshots, and audits.
|
|
28
|
+
- **Editor** is required if this identity will apply reviewed changes.
|
|
29
|
+
8. Connect Analytics Ops:
|
|
6
30
|
|
|
7
|
-
|
|
31
|
+
```bash
|
|
32
|
+
analytics-ops setup \
|
|
33
|
+
--service-account /absolute/path/to/service-account.json
|
|
34
|
+
```
|
|
8
35
|
|
|
9
|
-
|
|
36
|
+
Setup verifies both APIs, lists the GA4 properties available to the service
|
|
37
|
+
account, lets you select one, and creates `config/analytics_ops.yml`.
|
|
38
|
+
|
|
39
|
+
After that, use normal commands without another credential option:
|
|
10
40
|
|
|
11
41
|
```bash
|
|
12
|
-
|
|
13
|
-
|
|
42
|
+
analytics-ops overview
|
|
43
|
+
analytics-ops report traffic
|
|
44
|
+
analytics-ops realtime
|
|
45
|
+
analytics-ops audit
|
|
14
46
|
```
|
|
15
47
|
|
|
16
|
-
|
|
48
|
+
## What Analytics Ops remembers
|
|
49
|
+
|
|
50
|
+
Analytics Ops writes this user-level file:
|
|
17
51
|
|
|
18
|
-
|
|
19
|
-
|
|
52
|
+
```text
|
|
53
|
+
~/.config/analytics_ops/connection.json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
It contains only the absolute path to the service-account key. The connection
|
|
57
|
+
file is created atomically with mode `0600`, and its directory uses mode
|
|
58
|
+
`0700`. Analytics Ops does not copy the key or place its contents in project
|
|
59
|
+
configuration.
|
|
20
60
|
|
|
21
|
-
|
|
61
|
+
Keep the key in a stable location. Moving or deleting it requires setup again:
|
|
22
62
|
|
|
23
63
|
```bash
|
|
24
|
-
analytics-ops
|
|
64
|
+
analytics-ops setup \
|
|
65
|
+
--service-account /new/absolute/path/to/service-account.json
|
|
25
66
|
```
|
|
26
67
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
68
|
+
One service account can access several GA4 accounts. Add the same
|
|
69
|
+
service-account email at account level in each GA4 account.
|
|
70
|
+
|
|
71
|
+
## Read and edit access
|
|
72
|
+
|
|
73
|
+
Normal commands request only Google's `analytics.readonly` scope. The guarded
|
|
74
|
+
`apply` command requests `analytics.edit` in addition to read access.
|
|
32
75
|
|
|
33
|
-
|
|
76
|
+
Scopes do not grant GA4 access by themselves. The service account must also
|
|
77
|
+
have the matching Viewer or Editor role in GA4 Access Management.
|
|
34
78
|
|
|
35
|
-
|
|
36
|
-
|
|
79
|
+
Analytics Ops still requires a saved plan, explicit confirmation, and a fresh
|
|
80
|
+
matching snapshot before any apply. Merely configuring an Editor identity
|
|
81
|
+
does not cause writes.
|
|
82
|
+
|
|
83
|
+
## Automation
|
|
84
|
+
|
|
85
|
+
Use the same service-account setup non-interactively:
|
|
37
86
|
|
|
38
87
|
```bash
|
|
39
|
-
|
|
40
|
-
--
|
|
88
|
+
analytics-ops setup \
|
|
89
|
+
--service-account /secure/path/service-account.json \
|
|
90
|
+
--property 123456789 \
|
|
91
|
+
--non-interactive \
|
|
92
|
+
--json
|
|
41
93
|
```
|
|
42
94
|
|
|
43
|
-
Keep
|
|
44
|
-
|
|
95
|
+
Keep the JSON key in the CI platform's protected secret-file storage. Never
|
|
96
|
+
put its contents in an environment variable, command argument, repository, or
|
|
97
|
+
build log.
|
|
45
98
|
|
|
46
|
-
##
|
|
99
|
+
## Ruby API
|
|
47
100
|
|
|
48
|
-
|
|
101
|
+
The Ruby API can use an explicit service account without changing the saved
|
|
102
|
+
user connection:
|
|
49
103
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
-
|
|
104
|
+
```ruby
|
|
105
|
+
service_account = AnalyticsOps::ServiceAccount.new(
|
|
106
|
+
"/secure/path/service-account.json"
|
|
107
|
+
)
|
|
53
108
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
109
|
+
workspace = AnalyticsOps::Workspace.load(
|
|
110
|
+
"config/analytics_ops.yml",
|
|
111
|
+
profile: "production",
|
|
112
|
+
service_account: service_account
|
|
113
|
+
)
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Loading the identity reads and validates the local key. It does not contact
|
|
117
|
+
Google. Network access starts only when a connection or workspace operation is
|
|
118
|
+
called.
|
|
58
119
|
|
|
59
120
|
## Values that are easy to confuse
|
|
60
121
|
|
|
61
122
|
| Value | Example | Meaning |
|
|
62
123
|
| --- | --- | --- |
|
|
63
|
-
|
|
|
64
|
-
|
|
|
65
|
-
|
|
|
66
|
-
|
|
|
67
|
-
|
|
|
68
|
-
| Service
|
|
124
|
+
| GA4 account ID | `100000001` | Analytics container shown by discovery |
|
|
125
|
+
| GA4 property ID | `123456789` | Numeric reporting and configuration boundary |
|
|
126
|
+
| Stream ID | `987654321` | Numeric data-stream resource |
|
|
127
|
+
| Measurement ID | `G-EXAMPLE1` | Browser tagging ID; not a property or stream ID |
|
|
128
|
+
| Cloud project | `example-analytics-project` | Owns APIs, quota, and the service account |
|
|
129
|
+
| Service-account email | `analytics-ops@example-project.iam.gserviceaccount.com` | Identity added to GA4 Access Management |
|
|
130
|
+
| Service-account JSON | A downloaded private key file | Secret used by Analytics Ops; never commit it |
|
|
69
131
|
|
|
70
|
-
|
|
132
|
+
An API key identifies a Cloud project but cannot authorize access to private
|
|
133
|
+
GA4 data or settings.
|
|
71
134
|
|
|
72
|
-
|
|
73
|
-
private keys, API keys, or OAuth secrets in `analytics_ops.yml`.
|
|
74
|
-
- Never put credentials in a saved plan.
|
|
75
|
-
- Never commit service-account JSON.
|
|
76
|
-
- Never paste credentials into an issue, fixture, log, or report.
|
|
77
|
-
- Revoke or rotate credentials immediately after suspected exposure.
|
|
78
|
-
- Do not create a shared public OAuth client for this gem.
|
|
135
|
+
## Credential rules
|
|
79
136
|
|
|
80
|
-
|
|
81
|
-
|
|
137
|
+
- Never place the JSON key or its path in `analytics_ops.yml`.
|
|
138
|
+
- Never commit a service-account key.
|
|
139
|
+
- Never paste key contents into chat, issues, logs, screenshots, or reports.
|
|
140
|
+
- Never place production mutation credentials in a Rails web container.
|
|
141
|
+
- Revoke and replace a key immediately if it may have been exposed.
|
|
142
|
+
- Remove stale keys from the service account after rotation.
|
|
82
143
|
|
|
83
|
-
Official Google
|
|
144
|
+
Official Google references:
|
|
84
145
|
|
|
85
146
|
- [Admin API quickstart](https://developers.google.com/analytics/devguides/config/admin/v1/quickstart)
|
|
86
|
-
- [Data API quickstart](https://developers.google.com/analytics/devguides/reporting/data/v1/quickstart
|
|
147
|
+
- [Data API quickstart](https://developers.google.com/analytics/devguides/reporting/data/v1/quickstart)
|
data/docs/commands.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Commands
|
|
2
2
|
|
|
3
|
-
The executable is `analytics-ops`.
|
|
3
|
+
The executable is `analytics-ops`. Commands that operate on one property use
|
|
4
4
|
`config/analytics_ops.yml` and the `production` profile unless overridden.
|
|
5
|
+
`setup`, `properties`, and `discover` work before that file exists.
|
|
5
6
|
|
|
6
7
|
```text
|
|
7
8
|
analytics-ops COMMAND [options]
|
|
@@ -10,22 +11,70 @@ analytics-ops COMMAND [options]
|
|
|
10
11
|
## Fast examples
|
|
11
12
|
|
|
12
13
|
```bash
|
|
14
|
+
analytics-ops setup --service-account /absolute/path/to/service-account.json
|
|
15
|
+
analytics-ops overview
|
|
16
|
+
analytics-ops properties
|
|
13
17
|
analytics-ops doctor
|
|
14
|
-
analytics-ops audit --
|
|
18
|
+
analytics-ops audit --json
|
|
15
19
|
analytics-ops plan --output tmp/ga4-plan.json
|
|
16
20
|
analytics-ops apply tmp/ga4-plan.json
|
|
17
|
-
analytics-ops report
|
|
18
|
-
analytics-ops realtime --
|
|
21
|
+
analytics-ops report landing-pages --csv
|
|
22
|
+
analytics-ops realtime --json
|
|
19
23
|
```
|
|
20
24
|
|
|
21
25
|
Only `apply` can write to Google.
|
|
22
26
|
|
|
23
|
-
##
|
|
27
|
+
## Setup
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
analytics-ops setup --service-account /absolute/path/to/service-account.json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Analytics Ops supports only service-account authentication. On the first run,
|
|
34
|
+
pass the downloaded JSON key explicitly. Setup then:
|
|
35
|
+
|
|
36
|
+
1. Validates that the file is a Google service-account key.
|
|
37
|
+
2. Lists accessible accounts and properties without loading YAML.
|
|
38
|
+
3. Prompts with numbered choices showing account, property name, and ID.
|
|
39
|
+
4. Proves Admin and Data API read access.
|
|
40
|
+
5. Creates the smallest valid `config/analytics_ops.yml` using the
|
|
41
|
+
`production` profile.
|
|
42
|
+
6. Stores only the key's absolute path in
|
|
43
|
+
`~/.config/analytics_ops/connection.json` with mode `0600`.
|
|
44
|
+
7. Prints `analytics-ops overview` as the next command.
|
|
45
|
+
|
|
46
|
+
Setup never overwrites an existing profile that targets another property. A
|
|
47
|
+
matching file is a successful no-op. The key is never copied into a project or
|
|
48
|
+
printed.
|
|
49
|
+
|
|
50
|
+
Later setup runs use the remembered path:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
analytics-ops setup
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Automation uses the same single route with an explicit property:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
analytics-ops setup \
|
|
60
|
+
--service-account /secure/path/service-account.json \
|
|
61
|
+
--property 123456789 \
|
|
62
|
+
--non-interactive \
|
|
63
|
+
--json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The CLI never consults `gcloud`, browser login, Application Default
|
|
67
|
+
Credentials, `GOOGLE_APPLICATION_CREDENTIALS`, or API keys.
|
|
68
|
+
|
|
69
|
+
## Commands that do not change GA4
|
|
24
70
|
|
|
25
71
|
| Command | Result |
|
|
26
72
|
| --- | --- |
|
|
73
|
+
| `setup` | Loads the service account, selects a property, verifies both APIs, and writes local configuration; never changes Google Analytics |
|
|
74
|
+
| `properties` | Lists accessible account and property summaries without configuration or per-property stream calls |
|
|
27
75
|
| `doctor` | Checks the local file, credentials, Admin API, Data API, property access, client versions, edit visibility, and clock |
|
|
28
|
-
| `discover` | Lists accessible account IDs, property IDs, and stream IDs |
|
|
76
|
+
| `discover` | Lists accessible account IDs, property IDs, and stream IDs without configuration |
|
|
77
|
+
| `overview` | Returns five bounded reports for the previous 28 complete days in one batch request |
|
|
29
78
|
| `snapshot` | Prints normalized managed remote state and its fingerprint |
|
|
30
79
|
| `audit` | Compares desired state with a fresh snapshot; exits 2 for drift |
|
|
31
80
|
| `plan` | Generates the same comparison; `--output FILE` saves its exact JSON |
|
|
@@ -34,9 +83,8 @@ Only `apply` can write to Google.
|
|
|
34
83
|
| `realtime [NAME]` | Runs `realtime_events` by default |
|
|
35
84
|
| `schema` | Prints the version-1 configuration schema |
|
|
36
85
|
|
|
37
|
-
`doctor`
|
|
38
|
-
|
|
39
|
-
calls instead.
|
|
86
|
+
`doctor` uses the read-only Analytics scope and proves effective access with
|
|
87
|
+
small real calls to both APIs.
|
|
40
88
|
|
|
41
89
|
## Apply
|
|
42
90
|
|
|
@@ -69,23 +117,28 @@ plans and applies in one step.
|
|
|
69
117
|
| `-c, --config PATH` | Configuration file |
|
|
70
118
|
| `-p, --profile NAME` | Profile inside the file |
|
|
71
119
|
| `-f, --format FORMAT` | `human`, `json`, or report-only `csv` |
|
|
120
|
+
| `--json` | Shortcut for `--format json` |
|
|
121
|
+
| `--csv` | Shortcut for `--format csv` |
|
|
72
122
|
| `-o, --output PATH` | Save generated JSON; valid only with `plan` |
|
|
123
|
+
| `--property ID` | Select an accessible property without prompting; setup only |
|
|
124
|
+
| `--service-account PATH` | Connect a Google service-account JSON key; setup only |
|
|
73
125
|
| `--transport grpc|rest` | Official Google-client transport |
|
|
74
|
-
| `--timeout SECONDS` |
|
|
126
|
+
| `--timeout SECONDS` | Finite positive API call timeout |
|
|
75
127
|
| `--log-level LEVEL` | Structured request metadata: `debug`, `info`, `warn`, or `error`; default `warn` |
|
|
76
128
|
| `--yes` | Approve every operation in a saved plan; apply only |
|
|
77
|
-
| `--non-interactive` | Never prompt; apply
|
|
129
|
+
| `--non-interactive` | Never prompt; apply requires `--yes`, setup requires `--property` |
|
|
78
130
|
|
|
79
|
-
Unknown arguments
|
|
80
|
-
for anything except report results.
|
|
81
|
-
|
|
131
|
+
Unknown arguments, conflicting format flags, and non-finite timeouts fail
|
|
132
|
+
instead of being ignored. CSV is rejected for anything except report results.
|
|
133
|
+
CSV cells whose first meaningful character is a spreadsheet formula marker
|
|
134
|
+
are prefixed safely, including cells hidden behind whitespace or controls.
|
|
82
135
|
|
|
83
136
|
## Output
|
|
84
137
|
|
|
85
|
-
- Human output
|
|
138
|
+
- Human output removes terminal control characters from remote text.
|
|
86
139
|
- JSON output uses stable gem-owned fields and structured errors.
|
|
87
|
-
- CSV contains report headers and rows only; it
|
|
88
|
-
snapshots,
|
|
140
|
+
- CSV contains one report's headers and rows only; it is rejected for batched
|
|
141
|
+
overviews, plans, snapshots, and errors.
|
|
89
142
|
|
|
90
143
|
No command prints credentials or generated Google protobuf objects. Report
|
|
91
144
|
rows are emitted only because the user requested a report; they are never
|
|
@@ -107,6 +160,7 @@ logged automatically.
|
|
|
107
160
|
| 78 | Unsupported installed-client capability |
|
|
108
161
|
| 79 | Stale saved plan |
|
|
109
162
|
| 80 | Partial apply; inspect reconciliation output |
|
|
163
|
+
| 130 | Interrupted by the user; no Ruby backtrace is printed |
|
|
110
164
|
|
|
111
165
|
When `--format json` is selected, errors are JSON on standard error and are
|
|
112
166
|
suitable for automation.
|
|
@@ -80,13 +80,16 @@
|
|
|
80
80
|
"required": ["event_data", "user_data", "reset_on_new_activity"],
|
|
81
81
|
"properties": {
|
|
82
82
|
"event_data": { "$ref": "#/$defs/retentionValue" },
|
|
83
|
-
"user_data": { "$ref": "#/$defs/
|
|
83
|
+
"user_data": { "$ref": "#/$defs/userRetentionValue" },
|
|
84
84
|
"reset_on_new_activity": { "type": "boolean" }
|
|
85
85
|
}
|
|
86
86
|
},
|
|
87
87
|
"retentionValue": {
|
|
88
88
|
"enum": ["2_months", "14_months", "26_months", "38_months", "50_months"]
|
|
89
89
|
},
|
|
90
|
+
"userRetentionValue": {
|
|
91
|
+
"enum": ["2_months", "14_months"]
|
|
92
|
+
},
|
|
90
93
|
"googleSignals": {
|
|
91
94
|
"type": "object",
|
|
92
95
|
"additionalProperties": false,
|
|
@@ -102,11 +105,32 @@
|
|
|
102
105
|
"required": ["parameter_name", "display_name", "scope"],
|
|
103
106
|
"properties": {
|
|
104
107
|
"parameter_name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_]{0,39}$" },
|
|
105
|
-
"display_name": { "type": "string", "
|
|
106
|
-
"description": {
|
|
108
|
+
"display_name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_ ]{0,81}$" },
|
|
109
|
+
"description": {
|
|
110
|
+
"type": "string",
|
|
111
|
+
"maxLength": 150,
|
|
112
|
+
"pattern": "^[^\\u0000-\\u001F\\u007F]*$"
|
|
113
|
+
},
|
|
107
114
|
"scope": { "enum": ["event", "user", "item"] },
|
|
108
115
|
"disallow_ads_personalization": { "type": "boolean" }
|
|
109
|
-
}
|
|
116
|
+
},
|
|
117
|
+
"allOf": [
|
|
118
|
+
{
|
|
119
|
+
"if": { "properties": { "scope": { "const": "user" } } },
|
|
120
|
+
"then": {
|
|
121
|
+
"properties": {
|
|
122
|
+
"parameter_name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_]{0,23}$" }
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"if": {
|
|
128
|
+
"required": ["disallow_ads_personalization"],
|
|
129
|
+
"properties": { "disallow_ads_personalization": { "const": true } }
|
|
130
|
+
},
|
|
131
|
+
"then": { "properties": { "scope": { "const": "user" } } }
|
|
132
|
+
}
|
|
133
|
+
]
|
|
110
134
|
},
|
|
111
135
|
"customMetric": {
|
|
112
136
|
"type": "object",
|
|
@@ -114,16 +138,38 @@
|
|
|
114
138
|
"required": ["parameter_name", "display_name", "scope"],
|
|
115
139
|
"properties": {
|
|
116
140
|
"parameter_name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_]{0,39}$" },
|
|
117
|
-
"display_name": { "type": "string", "
|
|
118
|
-
"description": {
|
|
141
|
+
"display_name": { "type": "string", "pattern": "^[A-Za-z][A-Za-z0-9_ ]{0,81}$" },
|
|
142
|
+
"description": {
|
|
143
|
+
"type": "string",
|
|
144
|
+
"maxLength": 150,
|
|
145
|
+
"pattern": "^[^\\u0000-\\u001F\\u007F]*$"
|
|
146
|
+
},
|
|
119
147
|
"scope": { "const": "event" },
|
|
120
148
|
"measurement_unit": {
|
|
121
149
|
"enum": [
|
|
122
150
|
"standard", "currency", "feet", "meters", "kilometers", "miles",
|
|
123
151
|
"milliseconds", "seconds", "minutes", "hours"
|
|
124
152
|
]
|
|
153
|
+
},
|
|
154
|
+
"restricted_metric_types": {
|
|
155
|
+
"type": "array",
|
|
156
|
+
"uniqueItems": true,
|
|
157
|
+
"items": { "enum": ["cost_data", "revenue_data"] }
|
|
125
158
|
}
|
|
126
|
-
}
|
|
159
|
+
},
|
|
160
|
+
"allOf": [
|
|
161
|
+
{
|
|
162
|
+
"if": {
|
|
163
|
+
"required": ["measurement_unit"],
|
|
164
|
+
"properties": { "measurement_unit": { "const": "currency" } }
|
|
165
|
+
},
|
|
166
|
+
"then": {
|
|
167
|
+
"required": ["restricted_metric_types"],
|
|
168
|
+
"properties": { "restricted_metric_types": { "minItems": 1 } }
|
|
169
|
+
},
|
|
170
|
+
"else": { "properties": { "restricted_metric_types": { "maxItems": 0 } } }
|
|
171
|
+
}
|
|
172
|
+
]
|
|
127
173
|
}
|
|
128
174
|
}
|
|
129
175
|
}
|
data/docs/configuration.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
Analytics Ops reads strict, versioned YAML. The file describes desired GA4
|
|
4
4
|
state; it never contains credentials.
|
|
5
5
|
|
|
6
|
+
For the normal first run, let setup create the file after you choose a
|
|
7
|
+
property:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
analytics-ops setup --service-account /absolute/path/to/service-account.json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Setup writes only a quoted property ID under the `production` profile. It
|
|
14
|
+
will reuse a matching file but will not overwrite an existing profile that
|
|
15
|
+
targets another property.
|
|
16
|
+
|
|
6
17
|
## Smallest valid file
|
|
7
18
|
|
|
8
19
|
```yaml
|
|
@@ -44,7 +55,7 @@ profiles:
|
|
|
44
55
|
default_uri: "https://www.example.test"
|
|
45
56
|
|
|
46
57
|
# Accepted only as an explicit experimental declaration.
|
|
47
|
-
# Version 0.
|
|
58
|
+
# Version 0.2.0 reports a finding and does not apply this setting.
|
|
48
59
|
enhanced_measurement:
|
|
49
60
|
enabled: true
|
|
50
61
|
experimental: true
|
|
@@ -75,13 +86,16 @@ profiles:
|
|
|
75
86
|
description: Non-sensitive calculated estimate
|
|
76
87
|
scope: event
|
|
77
88
|
measurement_unit: currency
|
|
89
|
+
# Google requires currency metrics to be classified explicitly.
|
|
90
|
+
restricted_metric_types:
|
|
91
|
+
- revenue_data
|
|
78
92
|
|
|
79
93
|
# Checklist findings only; Analytics Ops does not claim to manage these.
|
|
80
94
|
manual_requirements:
|
|
81
95
|
- email_redaction_enabled
|
|
82
96
|
- consent_mode_reviewed
|
|
83
97
|
|
|
84
|
-
# Explicit declaration only in 0.
|
|
98
|
+
# Explicit declaration only in 0.2.0; never silently applied.
|
|
85
99
|
google_signals:
|
|
86
100
|
state: disabled
|
|
87
101
|
experimental: true
|
|
@@ -102,12 +116,13 @@ All three fields are required when `retention` is present:
|
|
|
102
116
|
|
|
103
117
|
- `event_data`: `2_months`, `14_months`, `26_months`, `38_months`, or
|
|
104
118
|
`50_months`
|
|
105
|
-
- `user_data`:
|
|
119
|
+
- `user_data`: `2_months` or `14_months`
|
|
106
120
|
- `reset_on_new_activity`: `true` or `false`
|
|
107
121
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
122
|
+
The 26-, 38-, and 50-month event periods are available only to Analytics 360
|
|
123
|
+
properties. Google does not allow those periods for user data, so Analytics
|
|
124
|
+
Ops rejects them locally. An API rejection for an ineligible event period is
|
|
125
|
+
returned as a typed error; the gem never substitutes a different period.
|
|
111
126
|
|
|
112
127
|
### Key events
|
|
113
128
|
|
|
@@ -119,6 +134,8 @@ substitute a different period.
|
|
|
119
134
|
Required fields are `parameter_name`, `display_name`, and `scope`.
|
|
120
135
|
Supported scopes are `event`, `user`, and `item`.
|
|
121
136
|
`disallow_ads_personalization` is valid only for user-scoped dimensions.
|
|
137
|
+
Display names must start with a letter and contain only letters, numbers,
|
|
138
|
+
spaces, and underscores, matching Google's create/update contract.
|
|
122
139
|
|
|
123
140
|
Identity is `scope + parameter_name`; display name and description are
|
|
124
141
|
mutable. Immutable conflicts are findings, not automatic replacement.
|
|
@@ -131,8 +148,14 @@ Required fields are `parameter_name`, `display_name`, and
|
|
|
131
148
|
`standard`, `currency`, `feet`, `meters`, `kilometers`, `miles`,
|
|
132
149
|
`milliseconds`, `seconds`, `minutes`, and `hours`.
|
|
133
150
|
|
|
134
|
-
|
|
135
|
-
|
|
151
|
+
A `currency` metric also requires `restricted_metric_types` containing
|
|
152
|
+
`cost_data`, `revenue_data`, or both. This classification controls restricted
|
|
153
|
+
data access in Google Analytics, so Analytics Ops never guesses it. The field
|
|
154
|
+
must be omitted or empty for non-currency metrics.
|
|
155
|
+
|
|
156
|
+
Identity is `parameter_name`. Scope, unit, and restricted-data classification
|
|
157
|
+
are treated as immutable; Analytics Ops will not archive and recreate a
|
|
158
|
+
conflicting metric.
|
|
136
159
|
|
|
137
160
|
## Environment variables
|
|
138
161
|
|
|
@@ -151,8 +174,9 @@ execution, YAML alias support, or Ruby-object deserialization.
|
|
|
151
174
|
## Strict safety rules
|
|
152
175
|
|
|
153
176
|
- The file is limited to 1 MiB.
|
|
177
|
+
- YAML nesting is bounded and duplicate mapping keys are rejected.
|
|
154
178
|
- Unknown fields fail closed.
|
|
155
|
-
- Secret-shaped fields
|
|
179
|
+
- Secret-shaped fields and credential-shaped values fail closed.
|
|
156
180
|
- Numeric identifiers must be YAML strings.
|
|
157
181
|
- User-visible strings reject control characters.
|
|
158
182
|
- Duplicate resource identities fail validation.
|
|
@@ -9,6 +9,7 @@ second HTTP stack and does not expose generated Google objects publicly.
|
|
|
9
9
|
| --- | --- | --- |
|
|
10
10
|
| `google-analytics-admin` | `~> 0.8.0` | 0.8.0 |
|
|
11
11
|
| `google-analytics-data` | `~> 0.9.0` | 0.9.0 |
|
|
12
|
+
| `googleauth` | `~> 1.12` | 1.17.1 |
|
|
12
13
|
|
|
13
14
|
The reviewed lockfile resolves these generated transports:
|
|
14
15
|
|
|
@@ -22,10 +23,10 @@ transport name does not make every feature Alpha: Google publishes feature
|
|
|
22
23
|
maturity separately. Analytics Ops treats capabilities Google identifies as
|
|
23
24
|
Alpha as experimental or unsupported.
|
|
24
25
|
|
|
25
|
-
The
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
transport.
|
|
26
|
+
The API-wrapper bounds allow reviewed patch updates inside each minor line and
|
|
27
|
+
reject a new minor contract automatically. The `googleauth` bound stays within
|
|
28
|
+
its compatible 1.x public API. `doctor` reports the installed Admin and Data
|
|
29
|
+
wrapper versions, expected bounds, and selected `grpc` or `rest` transport.
|
|
29
30
|
|
|
30
31
|
## Executable contract coverage
|
|
31
32
|
|
|
@@ -40,11 +41,14 @@ protobuf classes for:
|
|
|
40
41
|
- `list_key_events` and `create_key_event`
|
|
41
42
|
- list/create/update custom dimensions
|
|
42
43
|
- list/create/update custom metrics
|
|
44
|
+
- custom-metric restricted cost/revenue enum translation
|
|
43
45
|
- update web data-stream default URI
|
|
44
|
-
- `run_report` and `run_realtime_report`
|
|
46
|
+
- `run_report`, `batch_run_reports`, and `run_realtime_report`
|
|
45
47
|
|
|
46
48
|
The tests also prove enum mappings and normalization into immutable gem-owned
|
|
47
|
-
values without making network requests.
|
|
49
|
+
values without making network requests. Service-account tests exercise the
|
|
50
|
+
official `Google::Auth::ServiceAccountCredentials` loader with generated fake
|
|
51
|
+
keys and verify the exact read/edit scopes.
|
|
48
52
|
|
|
49
53
|
## Updating a Google client
|
|
50
54
|
|