Skip to content

Commit 52c5918

Browse files
committed
Merge branch 'ua/os-version-capability' into jch
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 ec0acc1 + 3ca5d12 commit 52c5918

File tree

6 files changed

+115
-24
lines changed

6 files changed

+115
-24
lines changed

Documentation/gitprotocol-v2.adoc

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,14 @@ 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
190-
and debugging purposes, and MUST NOT be used to programmatically assume
191-
the presence or absence of particular features.
187+
printable ASCII characters (i.e., the byte range 31 < x < 127), and are
188+
typically of the form "package/version os" (e.g., "git/1.8.3.1 Linux")
189+
where `os` is the operating system name (e.g., "Linux"). `X` and `Y` can
190+
be configured using the GIT_USER_AGENT environment variable and it takes
191+
priority. The `os` is retrieved using the 'sysname' field of the `uname(2)`
192+
system call or its equivalent. The agent strings are purely informative for
193+
statistics and debugging purposes, and MUST NOT be used to programmatically
194+
assume the presence or absence of particular features.
192195
193196
ls-refs
194197
~~~~~~~

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);

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+
redact_non_printables(&buf);
73+
74+
if (!getenv("GIT_USER_AGENT")) {
75+
strbuf_addch(&buf, ' ');
76+
strbuf_addstr(&buf, os_info());
3977
}
40-
agent = buf.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)