Skip to content

Commit 64a3501

Browse files
committed
Merge branch 'ua/os-version-capability' into seen
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 5c04e7a + 77908e7 commit 64a3501

File tree

8 files changed

+139
-20
lines changed

8 files changed

+139
-20
lines changed

Documentation/config/transfer.adoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,11 @@ transfer.bundleURI::
125125
transfer.advertiseObjectInfo::
126126
When `true`, the `object-info` capability is advertised by
127127
servers. Defaults to false.
128+
129+
transfer.advertiseOSInfo::
130+
When `true`, both the client and server independently append their
131+
operating system name (os) to the `agent` capability value. The `agent`
132+
capability will now be in form of "package/version os" (e.g.,
133+
"git/1.8.3.1 Linux"). When `false`, the `agent` capability will be
134+
in the form of "package/version" e.g "git/1.8.3.1". The server's
135+
configuration is independent of the client's. Defaults to `true`.

Documentation/gitprotocol-v2.adoc

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -184,11 +184,16 @@ 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 32 < 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. If `transfer.advertiseOSInfo` is `false` on the server, the server
192+
omits the `os` from X. If it is `false` on the client, the client omits the
193+
`os` from `Y`. The `os` is retrieved using the 'sysname' field of the `uname(2)`
194+
system call or its equivalent. The agent strings are purely informative for
195+
statistics and debugging purposes, and MUST NOT be used to programmatically
196+
assume the presence or absence of particular features.
192197
193198
ls-refs
194199
~~~~~~~

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/t5555-http-smart-common.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,17 @@ test_expect_success 'git receive-pack --advertise-refs: v1' '
123123
'
124124

125125
test_expect_success 'git upload-pack --advertise-refs: v2' '
126+
printf "agent=FAKE" >agent_capability &&
127+
if test_have_prereq WINDOWS
128+
then
129+
printf "\n" >>agent_capability &&
130+
git config transfer.advertiseOSInfo false
131+
else
132+
printf " %s\n" $(uname -s | test_redact_non_printables) >>agent_capability
133+
fi &&
126134
cat >expect <<-EOF &&
127135
version 2
128-
agent=FAKE
136+
$(cat agent_capability)
129137
ls-refs=unborn
130138
fetch=shallow wait-for-done
131139
server-option

t/t5701-git-serve.sh

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,22 +7,35 @@ 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 "\n" >>agent_capability &&
21+
git config transfer.advertiseOSInfo false
22+
else
23+
printf " %s\n" $(uname -s | test_redact_non_printables) >>agent_capability
24+
fi &&
1525
cat >expect.base <<-EOF &&
1626
version 2
17-
agent=git/$(git version | cut -d" " -f3)
27+
$(cat agent_capability)
1828
ls-refs=unborn
1929
fetch=shallow wait-for-done
2030
server-option
2131
object-format=$(test_oid algo)
2232
EOF
23-
cat >expect.trailer <<-EOF &&
33+
cat >expect.trailer <<-EOF
2434
0000
2535
EOF
36+
'
37+
38+
test_expect_success 'test capability advertisement' '
2639
cat expect.base expect.trailer >expect &&
2740
2841
GIT_TEST_SIDEBAND_ALL=0 test-tool serve-v2 \

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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#define USE_THE_REPOSITORY_VARIABLE
2+
13
#include "git-compat-util.h"
24
#include "version.h"
35
#include "strbuf.h"
@@ -9,9 +11,16 @@
911
# include GIT_VERSION_H
1012
#endif
1113

14+
#include "gettext.h"
15+
#include "config.h"
16+
1217
const char git_version_string[] = GIT_VERSION;
1318
const char git_built_from_commit_string[] = GIT_BUILT_FROM_COMMIT;
1419

20+
/*
21+
* Trim and replace each character with ascii code below 32 or above
22+
* 127 (included) using a dot '.' character.
23+
*/
1524
void redact_non_printables(struct strbuf *buf)
1625
{
1726
strbuf_trim(buf);
@@ -43,8 +52,63 @@ const char *git_user_agent_sanitized(void)
4352

4453
strbuf_addstr(&buf, git_user_agent());
4554
redact_non_printables(&buf);
55+
/* Add os name if the transfer.advertiseosinfo config is true */
56+
if (advertise_os_info()) {
57+
/* Add space to space character after git version string */
58+
strbuf_addch(&buf, ' ');
59+
strbuf_addstr(&buf, os_info_sanitized());
60+
}
4661
agent = strbuf_detach(&buf, NULL);
4762
}
4863

4964
return agent;
5065
}
66+
67+
int get_uname_info(struct strbuf *buf, unsigned int full)
68+
{
69+
struct utsname uname_info;
70+
71+
if (uname(&uname_info)) {
72+
strbuf_addf(buf, _("uname() failed with error '%s' (%d)\n"),
73+
strerror(errno),
74+
errno);
75+
return -1;
76+
}
77+
if (full)
78+
strbuf_addf(buf, "%s %s %s %s\n",
79+
uname_info.sysname,
80+
uname_info.release,
81+
uname_info.version,
82+
uname_info.machine);
83+
else
84+
strbuf_addf(buf, "%s\n", uname_info.sysname);
85+
return 0;
86+
}
87+
88+
const char *os_info_sanitized(void)
89+
{
90+
static const char *os = NULL;
91+
92+
if (!os) {
93+
struct strbuf buf = STRBUF_INIT;
94+
95+
get_uname_info(&buf, 0);
96+
/* Sanitize the os information immediately */
97+
redact_non_printables(&buf);
98+
os = strbuf_detach(&buf, NULL);
99+
}
100+
101+
return os;
102+
}
103+
104+
int advertise_os_info(void)
105+
{
106+
static int transfer_advertise_os_info= -1;
107+
108+
if (transfer_advertise_os_info == -1) {
109+
repo_config_get_bool(the_repository, "transfer.advertiseosinfo", &transfer_advertise_os_info);
110+
/* enabled by default */
111+
transfer_advertise_os_info = !!transfer_advertise_os_info;
112+
}
113+
return transfer_advertise_os_info;
114+
}

version.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
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

@@ -15,4 +17,24 @@ const char *git_user_agent_sanitized(void);
1517
*/
1618
void redact_non_printables(struct strbuf *buf);
1719

20+
/*
21+
Try to get information about the system using uname(2).
22+
Return -1 and put an error message into 'buf' in case of uname()
23+
error. Return 0 and put uname info into 'buf' otherwise.
24+
*/
25+
int get_uname_info(struct strbuf *buf, unsigned int full);
26+
27+
/*
28+
Retrieve, sanitize and cache operating system info for subsequent
29+
calls. Return a pointer to the sanitized operating system info
30+
string.
31+
*/
32+
const char *os_info_sanitized(void);
33+
34+
/*
35+
Retrieve and cache transfer.advertiseosinfo config value. Return 1
36+
if true, 0 if false.
37+
*/
38+
int advertise_os_info(void);
39+
1840
#endif /* VERSION_H */

0 commit comments

Comments
 (0)