Skip to content

Commit 89ad48d

Browse files
committed
Merge branch 'ua/os-version-capability' into next
The value of "uname -s" is by default sent over the wire as a new capability, with an opt-out for privacy-concious folks. * ua/os-version-capability: agent: advertise OS name via agent capability t5701: add setup test to remove side-effect dependency version: extend get_uname_info() to hide system details version: refactor get_uname_info() version: refactor redact_non_printables() version: replace manual ASCII checks with isprint() for clarity
2 parents e800811 + cf7ee48 commit 89ad48d

File tree

7 files changed

+115
-23
lines changed

7 files changed

+115
-23
lines changed

Documentation/gitprotocol-v2.adoc

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,13 @@ form `agent=X`) to notify the client that the server is running version
184184
the `agent` capability with a value `Y` (in the form `agent=Y`) in its
185185
request to the server (but it MUST NOT do so if the server did not
186186
advertise the agent capability). The `X` and `Y` strings may contain any
187-
printable ASCII characters except space (i.e., the byte range 32 < x <
188-
127), and are typically of the form "package/version" (e.g.,
189-
"git/1.8.3.1"). The agent strings are purely informative for statistics
187+
printable ASCII characters except space (i.e., the byte range 33 <= x <=
188+
126), and are typically of the form "package/version-os" (e.g.,
189+
"git/1.8.3.1-Linux") where `os` is the operating system name (e.g.,
190+
"Linux"). `X` and `Y` can be configured using the GIT_USER_AGENT
191+
environment variable and it takes priority. The `os` is
192+
retrieved using the 'sysname' field of the `uname(2)` system call
193+
or its equivalent. The agent strings are purely informative for statistics
190194
and debugging purposes, and MUST NOT be used to programmatically assume
191195
the presence or absence of particular features.
192196

builtin/bugreport.c

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
#include "diagnose.h"
1313
#include "object-file.h"
1414
#include "setup.h"
15+
#include "version.h"
1516

1617
static void get_system_info(struct strbuf *sys_info)
1718
{
18-
struct utsname uname_info;
1919
char *shell = NULL;
2020

2121
/* get git version from native cmd */
@@ -24,16 +24,7 @@ static void get_system_info(struct strbuf *sys_info)
2424

2525
/* system call for other version info */
2626
strbuf_addstr(sys_info, "uname: ");
27-
if (uname(&uname_info))
28-
strbuf_addf(sys_info, _("uname() failed with error '%s' (%d)\n"),
29-
strerror(errno),
30-
errno);
31-
else
32-
strbuf_addf(sys_info, "%s %s %s %s\n",
33-
uname_info.sysname,
34-
uname_info.release,
35-
uname_info.version,
36-
uname_info.machine);
27+
get_uname_info(sys_info, 1);
3728

3829
strbuf_addstr(sys_info, _("compiler info: "));
3930
get_compiler_info(sys_info);

connect.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ const char *parse_feature_value(const char *feature_list, const char *feature, s
624624
*offset = found + len - orig_start;
625625
return value;
626626
}
627-
/* feature with a value (e.g., "agent=git/1.2.3") */
627+
/* feature with a value (e.g., "agent=git/1.2.3-Linux") */
628628
else if (*value == '=') {
629629
size_t end;
630630

t/t5701-git-serve.sh

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,40 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
77

88
. ./test-lib.sh
99

10-
test_expect_success 'test capability advertisement' '
10+
test_expect_success 'setup to generate files with expected content' '
11+
printf "agent=git/%s" "$(git version | cut -d" " -f3)" >agent_capability &&
12+
1113
test_oid_cache <<-EOF &&
1214
wrong_algo sha1:sha256
1315
wrong_algo sha256:sha1
1416
EOF
17+
18+
if test_have_prereq WINDOWS
19+
then
20+
printf "agent=FAKE\n" >agent_capability
21+
else
22+
printf -- "-%s\n" $(uname -s | test_redact_non_printables) >>agent_capability
23+
fi &&
1524
cat >expect.base <<-EOF &&
1625
version 2
17-
agent=git/$(git version | cut -d" " -f3)
26+
$(cat agent_capability)
1827
ls-refs=unborn
1928
fetch=shallow wait-for-done
2029
server-option
2130
object-format=$(test_oid algo)
2231
EOF
23-
cat >expect.trailer <<-EOF &&
32+
cat >expect.trailer <<-EOF
2433
0000
2534
EOF
35+
'
36+
37+
test_expect_success 'test capability advertisement' '
2638
cat expect.base expect.trailer >expect &&
2739
40+
if test_have_prereq WINDOWS
41+
then
42+
GIT_USER_AGENT=FAKE && export GIT_USER_AGENT
43+
fi &&
2844
GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
2945
--advertise-capabilities >out &&
3046
test-tool pkt-line unpack <out >actual &&
@@ -355,6 +371,10 @@ test_expect_success 'test capability advertisement with uploadpack.advertiseBund
355371
expect.extra \
356372
expect.trailer >expect &&
357373
374+
if test_have_prereq WINDOWS
375+
then
376+
GIT_USER_AGENT=FAKE && export GIT_USER_AGENT
377+
fi &&
358378
GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \
359379
--advertise-capabilities >out &&
360380
test-tool pkt-line unpack <out >actual &&

t/test-lib-functions.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,3 +2043,11 @@ test_trailing_hash () {
20432043
test-tool hexdump |
20442044
sed "s/ //g"
20452045
}
2046+
2047+
# Trim and replace each character with ascii code below 32 or above
2048+
# 127 (included) using a dot '.' character.
2049+
# Octal intervals \001-\040 and \177-\377
2050+
# correspond to decimal intervals 1-32 and 127-255
2051+
test_redact_non_printables () {
2052+
tr -d "\n\r" | tr "[\001-\040][\177-\377]" "."
2053+
}

version.c

Lines changed: 64 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
#define USE_THE_REPOSITORY_VARIABLE
2+
13
#include "git-compat-util.h"
24
#include "version.h"
35
#include "strbuf.h"
6+
#include "gettext.h"
47

58
#ifndef GIT_VERSION_H
69
# include "version-def.h"
@@ -11,6 +14,19 @@
1114
const char git_version_string[] = GIT_VERSION;
1215
const char git_built_from_commit_string[] = GIT_BUILT_FROM_COMMIT;
1316

17+
/*
18+
* Trim and replace each character with ascii code below 32 or above
19+
* 127 (included) using a dot '.' character.
20+
*/
21+
static void redact_non_printables(struct strbuf *buf)
22+
{
23+
strbuf_trim(buf);
24+
for (size_t i = 0; i < buf->len; i++) {
25+
if (!isprint(buf->buf[i]) || buf->buf[i] == ' ')
26+
buf->buf[i] = '.';
27+
}
28+
}
29+
1430
const char *git_user_agent(void)
1531
{
1632
static const char *agent = NULL;
@@ -24,6 +40,27 @@ const char *git_user_agent(void)
2440
return agent;
2541
}
2642

43+
/*
44+
Retrieve, sanitize and cache operating system info for subsequent
45+
calls. Return a pointer to the sanitized operating system info
46+
string.
47+
*/
48+
static const char *os_info(void)
49+
{
50+
static const char *os = NULL;
51+
52+
if (!os) {
53+
struct strbuf buf = STRBUF_INIT;
54+
55+
get_uname_info(&buf, 0);
56+
/* Sanitize the os information immediately */
57+
redact_non_printables(&buf);
58+
os = strbuf_detach(&buf, NULL);
59+
}
60+
61+
return os;
62+
}
63+
2764
const char *git_user_agent_sanitized(void)
2865
{
2966
static const char *agent = NULL;
@@ -32,13 +69,35 @@ const char *git_user_agent_sanitized(void)
3269
struct strbuf buf = STRBUF_INIT;
3370

3471
strbuf_addstr(&buf, git_user_agent());
35-
strbuf_trim(&buf);
36-
for (size_t i = 0; i < buf.len; i++) {
37-
if (buf.buf[i] <= 32 || buf.buf[i] >= 127)
38-
buf.buf[i] = '.';
72+
73+
if (!getenv("GIT_USER_AGENT")) {
74+
strbuf_addch(&buf, '-');
75+
strbuf_addstr(&buf, os_info());
3976
}
40-
agent = buf.buf;
77+
redact_non_printables(&buf);
78+
agent = strbuf_detach(&buf, NULL);
4179
}
4280

4381
return agent;
4482
}
83+
84+
int get_uname_info(struct strbuf *buf, unsigned int full)
85+
{
86+
struct utsname uname_info;
87+
88+
if (uname(&uname_info)) {
89+
strbuf_addf(buf, _("uname() failed with error '%s' (%d)\n"),
90+
strerror(errno),
91+
errno);
92+
return -1;
93+
}
94+
if (full)
95+
strbuf_addf(buf, "%s %s %s %s\n",
96+
uname_info.sysname,
97+
uname_info.release,
98+
uname_info.version,
99+
uname_info.machine);
100+
else
101+
strbuf_addf(buf, "%s\n", uname_info.sysname);
102+
return 0;
103+
}

version.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,20 @@
11
#ifndef VERSION_H
22
#define VERSION_H
33

4+
struct repository;
5+
46
extern const char git_version_string[];
57
extern const char git_built_from_commit_string[];
68

79
const char *git_user_agent(void);
810
const char *git_user_agent_sanitized(void);
911

12+
/*
13+
Try to get information about the system using uname(2).
14+
Return -1 and put an error message into 'buf' in case of uname()
15+
error. Return 0 and put uname info into 'buf' otherwise.
16+
*/
17+
int get_uname_info(struct strbuf *buf, unsigned int full);
18+
19+
1020
#endif /* VERSION_H */

0 commit comments

Comments
 (0)